Set global TimeZone for DateFormatter - swift3

I searched here in SO but can't find useful thread to accomplish what I want. I'm new with Swift so I don't know much of this. So the scenario is I want to set a specific timezone which can be change by user with the app's settings. What I want is when the user changed the said timezone it should reflect through out the app. Yes I can set the timezone in each "DateFormatter" but I don't want to write it every time I create a DateFormatter.
Is there a way so when I create an instance of the DateFormatter the timezone is already set to the timezone the user selected? Is it possible to do this using an Extension of the DateFormatter?

What you can do is make extension of Date as of you are setting this TimeZone to DateFormatter to formate your date, So make two extension one for Date and one for String.
extension Date {
struct CustomDateFormatter {
static var currentTimeZone = TimeZone.current //Set default timeZone that you want
static func dateFormatter(withFormat format: String) -> DateFormatter {
let formatter = DateFormatter()
formatter.timeZone = CustomDateFormatter.currentTimeZone
formatter.dateFormat = format
return formatter
}
}
func toDateString(withFormat format: String) -> String {
return CustomDateFormatter.dateFormatter(withFormat: format).string(from: self)
}
}
extension String {
func toDate(withFormat format: String) -> Date? {
return Date.CustomDateFormatter.dateFormatter(withFormat: format).date(from: self)
}
}
Now when ever you need to set TimeZone or want to convert Date to String or vice versa use this extension like this.
//Set timezone
Date.CustomDateFormatter.currentTimeZone = TimeZone(abbreviation: "GMT")!
//get date from String
let date = "31-05-2017 07:30:05".toDate(withFormat: "dd-MM-yyyy HH:mm:ss")
//get string from date with specific format
let dateString = Date().toDateString(withFormat: "dd-MM-yyyy HH:mm:ss")

Related

How to get current filters from PowerBi embedded export report

I am using powerbi embedded and I would like an export button similar to the one used on powerbi.com, that asks if you want to apply the current filters or not.
How can I get the current filters in javaScript in such a way that these can be passed to the back end, or to the javascript api to generate a PDF?
I am using the following code to generate the PDF currently, I just don't know how to get the current configuration current filters and current page selected in javaScript
public PowerBiExportViewModel CreateExport(Guid groupId,
Guid reportId,
IEnumerable<PowerBiReportPage> reportPages,
FileFormat fileFormat,
string urlFilter,
TimeSpan timeOut)
{
var errorMessage = string.Empty;
Stream stream = null;
var fileSuffix = string.Empty;
var securityToken = GetAccessToken();
using (var client = new PowerBIClient(new Uri(BaseAddress), new TokenCredentials(securityToken, "Bearer")))
{
var powerBiReportExportConfiguration = new PowerBIReportExportConfiguration
{
Settings = new ExportReportSettings
{
Locale = "en-gb",
IncludeHiddenPages = false
},
Pages = reportPages?.Select(pn => new ExportReportPage { PageName = pn.Name }).ToList(),
ReportLevelFilters = !string.IsNullOrEmpty(urlFilter) ? new List<ExportFilter>() { new ExportFilter(urlFilter) } : null,
};
var exportRequest = new ExportReportRequest
{
Format = fileFormat,
PowerBIReportConfiguration = powerBiReportExportConfiguration
};
var export = client.Reports.ExportToFileInGroupAsync(groupId, reportId, exportRequest).Result;
You can go to PowerBi playground and play around with their sample report. Next to "Embed" button you have "Interact" and option to get filters. In response you get JSON with filters. If you are too lazy to go there, here is the code it created for me
// Get a reference to the embedded report HTML element
var embedContainer = $('#embedContainer')[0];
// Get a reference to the embedded report.
report = powerbi.get(embedContainer);
// Get the filters applied to the report.
try {
const filters = await report.getFilters();
Log.log(filters);
}
catch (errors) {
Log.log(errors);
}

Run CKQueryOperation with results from previous CKQueryOperation

I have an app that is a shopping list. I can store prices per product and vendor in my app, the model is
Product
Vendor
Price
One product can have multiple prices from different vendors.
I store the price information with references to the product and vendor (CKRecord.Reference).
Now I am using the below to fetch all the prices related to a product:
public func fetchDataByProduct(product: Product, completionHandler: #escaping (Bool) -> Void){
self.pricesBuffer = []
let cloudContainer = CKContainer.init(identifier: "iCloud.XYZ")
let publicDatabase = cloudContainer.publicCloudDatabase
let reference = CKRecord.Reference(recordID: product.recordID, action: .deleteSelf)
let predicate = NSPredicate(format: "priceToProduct == %#", reference)
let query = CKQuery(recordType: "Price", predicate: predicate)
let operation = CKQueryOperation(query: query)
operation.recordFetchedBlock = { record in
let price = Price()
price.recordID = record.recordID
price.grossPrice = record.object(forKey: "grossPrice") as? Double
let dummy = record.object(forKey: "priceToVendor") as! CKRecord.Reference
price.vendorRecordID = dummy.recordID
self.pricesBuffer.append(price)
}
operation.queryCompletionBlock = { [unowned self] (cursor, error) in
self.pricesBuffer.forEach({price in
price.retrieveVendor()
})
DispatchQueue.main.async {
if error == nil {
self.prices = self.pricesBuffer
completionHandler(true)
} else {
}
}
}
publicDatabase.add(operation)
}
My problem is now that I cannot retrieve the vendor name which is part of the Vendor object (Vendor.name).
I have tried to loop over the pricesBuffer and run this one per price but the problem seems to be that CloudKit first completes the initial request to fetchDataByProduct() and then afterwards fetches the vendor data but then its too late because that updated data does not get pushed to my View (SwiftUI).
publicDatabase.fetch(withRecordID: self.vendorRecordID, completionHandler:  {[unowned self] record, error in
if let record = record {
print(record)
self.vendor.recordID = record.recordID
self.vendor.name = record["name"] as! String
print(self.vendor.name)
}
})
Any ideas how to solve this? I believe I have to add a second CKQueryOperation to the mix and use the .addDependency() but I cannot wrap my head around how that should look like in the end.
Let's say you use the operation to fetch prices like above.
let predicate = NSPredicate(format: "priceToProduct == %#", reference)
let query = CKQuery(recordType: "Price", predicate: predicate)
let pricesOperation = CKQueryOperation(query: query)
pricesOperation.database = publicDatabase // not required if you don't use OperationQueue
Then you can construct operation to fetch vendors, I will create simple operation for demo purposes.
let vendorQuery = CKQuery(recordType: "Vendor", predicate: predicate)
let vendorsOperation = CKQueryOperation(query: vendorQuery)
vendorsOperation.database = publicDatabase // not required if you don't use OperationQueue
Then you can set dependency, first fetch prices than vendors.
vendorsOperation.addDependency(pricesOperation)
And lastly submit those operations to OperationQueue
let operationQueue = OperationQueue()
operationQueue.addOperations([pricesOperation, vendorsOperation], waitUntilFinished: false)
Edit: If you don't want to use OperationQueue, simply submit those operations to database, but first set dependency before submitting the operations to be executed.
vendorsOperation.addDependency(pricesOperation)
publicDatabase.add(pricesOperation)
publicDatabase.add(vendorsOperation)

if let ISO8601DateFormatter from String

I have a response that returns the date of an object and Sometimes it returns the year and sometimes returns the date with the ISO8601DateFormatter style (1995-01-01T00:00:00Z)
The question is how can i get a if let that can identify when the value is a year as String or a ISO8601Date from a string.
I ended up doing this:
let pulledDate = "1995-01-01T00:00:00Z"
let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withYear, .withMonth, .withDay, .withTime, .withDashSeparatorInDate, .withColonSeparatorInTime]
if let date = dateFormatter.date(from: pulledDate ?? ""){
let units: Set<Calendar.Component> = [.year]
let comps = Calendar.current.dateComponents(units, from: date)
print("It is a date year = \(comps.year)")
}
else{
print("It is not a date")
}

swift 3 how to subclass NSDate or Date

I'm trying to add a special JSONSerializable method to a dateTaken field so I wanted to extend Date. but I discovered that Date is a struct and cannot be extended, so NSDate. but I can't figure out how to get a DateTaken from a Date
class DateTaken : NSDate, JSONRepresentable {
static var formatter = DateFormatter()
var JSONRepresentation: AnyObject {
DateTaken.formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" // ISO8601
DateTaken.formatter.timeZone = NSTimeZone(abbreviation: "UTC") as TimeZone!
return DateTaken.formatter.string(from:self as Date) as AnyObject
}
var JSONLocalTimeRepresentation: AnyObject {
DateTaken.formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
return DateTaken.formatter.string(from:self as Date) as AnyObject
}
}
let d = Date()
let dateTaken : DateTaken = DateTaken.init(timeInterval: 0, since: d)
// exception
(lldb) p NSDate.init(timeInterval: 0, since: dateTaken)
(NSDate) $R0 = 0x0000000156e6fdb0 2014-10-13 08:49:18 UTC
(lldb) p dateTaken.init(timeInterval: 0, since: dateTaken)
error: <EXPR>:3:1: error: 'init' is a member of the type; use 'type(of: ...)' to initialize a new object of the same dynamic type
dateTaken.init(timeInterval: 0, since: dateTaken)
^
type(of: )
This isn't Java. We have extensions for this.
extension NSDate: JSONRepresentable {
static var formatter = DateFormatter()
var JSONRepresentation: AnyObject {
DateTaken.formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" // ISO8601
DateTaken.formatter.timeZone = TimeZone(abbreviation: "UTC")
return DateTaken.formatter.string(from: self as Date) as AnyObject
}
var JSONLocalTimeRepresentation: AnyObject {
DateTaken.formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
return DateTaken.formatter.string(from: self as Date) as AnyObject
}
}
I also suspect there's a bug in this caused by the sharing of formatter. After the timeZone is set for the first time in JSONRepresentation, JSONLocalTimeRepresentation will act like JSONRepresentation. I may be wrong, but I can't test it now. It's worth checking out.

How to find and replace date, on timebased trigger by using ScriptApp Custom function

I have a Google Document with only one date in the body of the document. I am trying to write a script that updates the date every 24 hours.
The date in the document is currently set to "11/01/2016" as text, 1 day less than today (12/01/2016). I assumed using a replaceText() would work.
This is my script at the moment.
ScriptApp.newTrigger("myFunction")
.timeBased()
.atHour(24)
.everyDays(1)
.inTimezone("GMT")
function myFunction()
{
var date = Utilities.formatDate(new Date(), "GMT", "dd/MM/yyy");
var doc = DocumentApp.openById("ID of Document");
doc.replaceText(date-1,date) ;
}
What I am doing wrong here?
You can't replace text on document object, you need to get document body. your date is a string, you can't get yesterday by date-1. refer the date conversion too.
function myFunction()
{
var body = DocumentApp.getActiveDocument().getBody();
var d = new Date();
var yesterdayDate = Utilities.formatDate(new Date(d.getTime()-1*(24*3600*1000)), "GMT", "dd/MM/yyy");
var todayDate = Utilities.formatDate(d, "GMT", "dd/MM/yyy");
body.replaceText(yesterdayDate,todayDate) ;
}