Remove time component from TimeInterval in Swift? - ios

I have a time component coming from a Json. I am trying to group objects according to their time posted.
I have a time interval like 1540432146 which is a double.
I am converting it to Date type using
guard let timeInMilliseconds = lastUpdateOn as? Double else {return NSDate()}
let timeInSeconds = timeInMilliseconds / 100000
print(timeInSeconds)
// get the Date
let dateTime = NSDate(timeIntervalSince1970: timeInSeconds)
Hence I am getting 2018-10-25 10:54:20.325076+0900 as the output.
Is it possible to remove the Time component of this and again converting the Date type back to TimeIntervalSincel1970 as I will using it later to sort my elements in an array and it would be easier to compare Double
func getTime(lastUpdateOn:Any) -> NSDate{
guard let timeInMilliseconds = lastUpdateOn as? Double else {return NSDate()}
let timeInSeconds = timeInMilliseconds / 100000
// get the Date
let dateTime = NSDate(timeIntervalSince1970: timeInSeconds)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd-MM-yyyy"
let datenew = dateFormatter.string(from: dateTime as Date)
let newDate = dateFormatter.date(from: datenew)
print(newDate)
return dateTime
}
This is the function I tried but it returns value (1970-06-27 15:00:00 +0000) always. What am I doing wrong ?

If your only goal is to compare different dates to see which one comes first, simply convert the Int Unix Timestamps from your JSON to Date objects with:
let aDate = Date(timeIntervalSince1970: Double(timestamp)/1000.0)
You can compare Date objects directly using >, =, <, etc, and the result will compare the dates down to the millisecond.
You can also compare your Unix timestamp values directly and the results will be identical to comparing timestamps that you've converted to Date objects.
If you want to compare Date objects just by month/day/year, its more complicated.
A Cocoa Date ALWAYS represents an instant in time, all over the world. Internally, it's represented as a number of seconds since the iOS "epoch date" (midnight on January 1st, 2001 in UTC) Unix uses a different epoch date, but using "timeIntervalSince1970" and it's variants lets you work with Cocoa Date objects and Unix epoch dates.
There is no such thing as a Date "without a time component". There are various ways you could "normalize" your dates: You can convert a date to a date string that only has the month/day/year; you can force all Date values to exactly midnight on their month/day/year in a given timezone, or you could extract month/day/year DateComponents from your Date. (Search on "DateComponents" in the Xcode help system, and also search for "DateComponents" in the Calendar class reference, as many of the functions that let you do calculations on Dates and DateComponents are provided by the Calendar class.)
Note that the day/month/year that a Unix numeric timestamp falls on is often different depending on your time zone. Right now it's 22:47 EDT on 24 October here in the DC suburbs. I just computed the Unix timestamp for the current time and got 1540435644000. In Japan, 1540435644000 is 25 October. (From my perspective, it's already tomorrow in Japan). So 2 Unix timestamps might be on the same day/month/year in Japan but on different day/month/years where I live, or visa-versa.

Related

Convert UTC time to PST in SWIFT

I need to convert the UTC time to PST
From backed, I get UTC dates like "2021-06-25T07:00:00Z"
I need to show the dates in Hstack from Provided UTC date to the current date.
I write the following code.
Anyone help to me.
func datesRange(from:Date, to:Date)->[Date]{
if from > to {return [Date]()}
var tmpdate = from
var array:[Date] = []
while tmpdate <= to {
array.append(tmpdate)
tmpdate = Calendar.current.date(byAdding: .day,value: 1, to: tmpdate)!
}
return array
}
extension Date{
func convertTimezone(timezone:String)-> Date{
if let targettimeZone = TimeZone(abbreviation: timezone){
let delta = TimeInterval(targettimeZone.secondsFromGMT(for: self) - TimeZone.current.secondsFromGMT(for: self))
return addingTimeInterval(delta)
}else{
return self
}
}
}
I used as follows
func getrangeDays(){
let startday = "2021-06-25T07:00:00Z"
let dateformater = DateFormatter()
dateformater.locale = Locale(identifier: "en_US_POSIX")
dateformater.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
if let date = dateformater.date(from: startday){
let rangedays = datesRange(from:date.convertTimezone(timezone: "PST") , to: Date().convertTimezone(timezone: "PST"))
print(rangedays)
}
}
Your convertTimezone() function does not make sense. It is trying to convert a Date to a different time zone. A Date object does not have a time zone. It is an instant in time, anywhere on the planet. Time zones only make sense when you want to display a Date, or do time zone specific date calculations. (And in that case you want to create a Calendar object and set its time zone to the desired time zone, then use that Calendar for your date calculations.)
Get rid of that function.
Convert your input date string to a Date as you are doing now (although you might want to use an ISO8601DateFormatter rather than a regular date formatter, since those are specifically intended for handling ISO8601 dates.)
Build your date range using your datesRange() function.
Then use a second DateFormatter to display your dates in PST. (Not convert Dates to PST. That doesn't make sense.)

Firebase & Swift - Date saved with UTC -7?

I'm trying to understand how exactly dates are saved in the CloudFirestore of Firebase...
When I put the current date in the database dateToSAve = Date() , this date is stored with UTC-7:
But in someone in France for example, want to save data on Firebase, it will be the current date -9 hours to conform with the UTC -7
And sometimes, because of that, it can be a different day...
Do you know how to handle this problem? I would like to save in the database, the current date of the user.
You should not store date object in database, instead you should save timestamp in UTC 0. And after retrieving that timestamp you can convert it back into date with the time portion in your current time zone.
For getting timestamp in UTC 0:
let timestamp = Date().timeIntervalSince1970
And for converting timestamp back to date with the time portion in your current timezone:
// gives date with time portion in UTC 0
let date = Date(timeIntervalSince1970: timestamp)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM-dd-yyyy" // change to your required format
dateFormatter.timeZone = TimeZone.current
// date with time portion in your specified timezone
print(dateFormatter.string(from: date))

Date format Convertion issue in swift

i could not convert string date into NSDate object.
Please check below code
let stringDate = "06:30 AM"
let formatter = NSDateFormatter()
formatter.dateFormat="hh:mm a"
let local = NSLocale(localeIdentifier: "en_US")
formatter.locale=local
let date = formatter.dateFromString(stringDate)
The output is as expected, and depending on what you're trying to achieve, you haven't really done anything wrong.
Your stringDate instance contains only information about a time of the day, not a date (the prior is also the only format your NSDateFormatter formatter is "interested" in). Hence, the following snippet produces the expected 06:30 AM output:
let stringDate = "06:30 AM"
let formatter = NSDateFormatter()
formatter.dateFormat="hh:mm a"
let local = NSLocale(localeIdentifier: "en_US")
formatter.locale=local
if let date = formatter.dateFromString(stringDate) {
print(formatter.stringFromDate(date)) // 06:30 AM
}
NSDate instances are defined, however, as single point in time (date and hour of the day), with reference to an absolute reference date:
NSDate objects encapsulate a single point in time, independent of
any particular calendrical system or time zone. Date objects are
immutable, representing an invariant time interval relative to an
absolute reference date (00:00:00 UTC on 1 January 2001).
From the language reference for NSDate.
Hence, in addition to a time of day, NSDate instances include also a date (even if this is not, in your case, used or displayed). When you assign a value to date above, the Swift playground displays the time of day of the correct date; the latter offset by 06:30 from the absolute reference date, 2000-01-01 00:00:00. If we modify the example above to print all details in the final print statement, we see this more clearly:
// ...
if let date = formatter.dateFromString(stringDate) {
formatter.dateStyle = .FullStyle
formatter.timeStyle = .FullStyle
print(formatter.stringFromDate(date))
/* Saturday, January 1, 2000 at 6:30:00 AM Central European Standard Time */
}
(Addition with regard to your comments below)
Note the difference of printing the date object itself (e.g. print(date) above) and printing a ** formatted string representation** of the date using your formatter (e.g. print(formatter.stringFromDate(date))). The prior just prints the .description property of your date, which is an default-formatted string representation of the contents of object itself rather than a controlled formatted output of the date:
Declaration
var description: String { get }
Description
A string representation of the date object. (read-only)
The representation is useful for debugging only.
There are a number of options to acquire a formatted string for a date
including: date formatters (see NSDateFormatter and Data Formatting
Guide), and the NSDate methods descriptionWithLocale:,
dateWithCalendarFormat:timeZone:, and
descriptionWithCalendarFormat:timeZone:locale:
Refer to my code blocks above to see how you can print the formatted date using your NSFormatter.

NSDateFormatter decreases the day of date

I need to store Date variable in CoreData in iOS
I need to store the Date only without the Time, So I made a formatter that discard the time partition from the NSDate variable.
But I have a strange result:
This is my code:
let dateStr = "2016-02-14 11:27:01"
let df2 = NSDateFormatter()
df2.timeZone = NSTimeZone.defaultTimeZone()
df2.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dateStr)
if let date = df2.dateFromString(dateStr) {
df2.dateFormat = "yyyy-MM-dd"
print("-> \(df2.dateFromString(df2.stringFromDate(date)))")
}
and this is the output:
2016-02-14 11:27:01
-> Optional(2016-02-13 20:00:00 +0000)
Why does the formatter decrease the day by one ?
I tried many dates with same issue
Your time zone is obviously UTC+4.
To get UTC set the time zone accordingly.
df2.timeZone = NSTimeZone(forSecondsFromGMT: 0)
But although you see a date 4 hours ago the NSDate object is treated correctly depending on your time zone. The print command displays always UTC ignoring the time zone information, because NSDate is just a wrapper for a Double number.

NSDateFormatter parses two-digit year as 2046 instead of 1946 or 2040 instead of 1940

I have a scenario where I'm getting a date string as "46-05-24" (yy-mm-dd), and I need to re-format the date as "1946-05-24". The NSDateFormatter interprets the string as "2046-05-24".
I'm using this code:
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yy-mm-dd"
let gmt : NSTimeZone = NSTimeZone(abbreviation: "GMT")!
dateFormatter.timeZone = gmt
let dateFromString = dateFormatter.dateFromString(date as String)
dateFormatter.dateFormat = "yyyy-mm-dd"
if dateFromString != nil{
let dateString = dateFormatter.stringFromDate(dateFromString!)
print(dateString)
}
Is there something I'm missing here?
It happens because if you're giving NSDateFormatter a two-digit year, it needs to decide what century that year is in. It does this using its twoDigitStartDate property, which sets the earliest date that a two-digit year can represent. It has a default value of December 31, 1949. A date in 46 falls on the low side of 50 so it gets treated as 2046.
You can change the value of twoDigitStartDate to adjust the results. For example, you could set it to a date exactly 100 years in the past. That would mean that any two-digit year would be interpreted as the most recent year with those two digits:
let oneCenturyAgo = NSCalendar.currentCalendar().dateByAddingUnit(NSCalendarUnit.Year, value: -100, toDate: NSDate(), options: NSCalendarOptions(rawValue:0))
dateFormatter.twoDigitStartDate = oneCenturyAgo
Of course if you get someone whose date is over 100 years ago, there's no good way for your code to know which year is appropriate. If the year is "10", was that person born in 1910 or 2010? You have no way of knowing, and all your code can do is make the best guess.
The cause of your problem is that your data omits some relevant information: the century. Using only the last two digits you as the dev have to decide which century the dates are in. If all of them are in the 20th century (1900 - 1999) you can use the following approach:
You could simply prepend 19 before the string to parse. Assuming date is the string that you want to parse you can use
let dateFromString = dateFormatter.dateFromString("19" + (date as String))
instead of your
let dateFromString = dateFormatter.dateFromString(date as String)
If the dates you are going to handle are in the 20th and the 21st century you are going to have a bad time because what year is 05 supposed to reflect? 1905? 2005? 2105?

Resources