Date output is different.So,can't compare correctly - swift

Here is my code.Please take a look first
import UIKit
var expireDate : Double = 1472647093
var date = NSDate(timeIntervalSince1970: expireDate)
print("Date : \(date)")
let current_date = NSDate()
if date.compare(current_date) == NSComparisonResult.OrderedDescending{
print("is Greater than current date")
}else if date.compare(current_date) == NSComparisonResult.OrderedAscending{
print("is Less than current date")
}else{
print("Same")
}
Here is the output on playground :
I really don't know why "Date : " output is different than date variable.My server send me an expire date format in unix timestamp which is long format.And I really need to compare it with current date.Actually
Aug 31, 2016, 7:08 PM // It has correct day/month/year but incorrect time
2016-08-31 12:38:13 +0000\n // has all correct time and date that the server send which was 12:38PM
So,why I am having greater than current date?And why it was 7:08PM instead of 12:38PM
Any help?
UPDATE :

You don't have wrong dates since Aug 31, 2016, 7:08 PM is your current timestamp, whereas in the print you have with timezone UTC. When you compare the dates they are both in UTC so you don't have any problems.

My above question has nothing wrong with it. I'm just misunderstood with the timezone or standard that I am dealing with. The server already send me expire date with my timezone locale in UTC standard format.
So,I don't need to change that expire date according to my current time zone.
All I have to do is get my current time,change it to UTC format using my current timezone. And compare server expire_date and current_date. Mission Accomplish.
// Using Expire Date
var expireDate : NSTimeInterval = 1472689452 // 00:24 AM UTC
var date = NSDate(timeIntervalSince1970: expireDate) // Since January 1 1970 Convert to NSDate
// Then I change this time format to UTC String without adding any timezone because its already included
var df_utc = NSDateFormatter()
df_utc.timeZone = NSTimeZone(name: "UTC")
df_utc.dateFormat = "yyyy.MM.dd G 'at' HH:mm:ss zzz"
// Get the expire date string by formatting it in UTC
var ts_utc_string : NSString = df_utc.stringFromDate(date)
// Getting current time of mine
var local_date = NSDate()
var df_local = NSDateFormatter()
df_local.timeZone = NSTimeZone(name: "MMT") // then use my locale to add that current time UTC [MMT +6:30]
df_local.dateFormat = "yyyy.MM.dd G 'at' HH:mm:ss zzz"
var ts_local_string : NSString = df_local.stringFromDate(local_date)
// Compare
if ts_local_string.compare(ts_utc_string as String) == NSComparisonResult.OrderedDescending{
print("CurrentTime is Greater than Expire Time")
}else if ts_local_string.compare(ts_utc_string as String) == NSComparisonResult.OrderedAscending{
print("CurrentTime is Less than Expire Time")
}else{
print("Same")
}
Here is the output :
For those who are still seeking for such problem like me, UTC was just a standard for timezone. If you need to compare it with your timezone, you just need to change your current time according to your country timezone.

Related

Swift Date formating changes to next month when using end of month data?

I live by end of month dates such as "2019-02-28 23:59:59"
print when I print out that date it tells me "Mar-2019". No it is still "Feb-2019"
print(dt1.toString(dateFormat: "MMM-YYYY")
I do use SwiftDate. I also get this issue with the DateFormatter().
so instead of clean code I end up having to subtracting a day to get the correct month-year to display.
Why?
You need to set Timezone & date format properly as below,
let string = "2019-02-28 23:59:59"
let df = DateFormatter()
df.timeZone = .current
df.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = df.date(from: string)
print(date?.description(with: .current)) //Thursday, February 28, 2019 at 11:59:59 PM Gulf Standard Time
df.dateFormat = "MMM-yyyy"
print(df.string(from: date!)) // Feb-2019

How to get a date from European time-only with DateFormatter in Swift

I try to get a date but I only have a time available.
For now, I don't care about year, month or day. All that matters is the time.
My input is in the form "hh:mm:ss" (i.e. European time format).
The problem is that any time above 12:59:59 does not work !
How can I get dates from times above 12:59:59 ????
My code looks like follows:
import UIKit
let str = "17:02:09"
let mydateFormatter = DateFormatter()
mydateFormatter.dateFormat = "hh:mm:ss"
let timezone = TimeZone(abbreviation: "CEST") ?? TimeZone.current
mydateFormatter.timeZone = timezone
mydateFormatter.locale = Locale(identifier: "de_DE") as Locale?
let date1 = mydateFormatter.date(from: str)
print(date1?.description ?? "no date available")
Output: no date available
If I set the str's hour setting to anything below or equal to 12, then it works.
For example, if I set str = "12:02:09", I get the output: 1999-12-31 23:02:09 +0000
For example, if I set str = "10:02:09, I get the output: 2000-01-01 09:02:09 +0000
For example, if I set str = "13:02:09, I get the output: no date available
How can I get dates from times above 12:59:59 ????
And ideally, how can I get dates that have a matching time with the input-time ?

Swift Date function do not work as Expected

I am trying to find out the difference between two date in seconds using Swift 4.1. This is the code I use,
func getDurationInSeconds(date1 :Date) -> Int{
guard let durationInSeconds = Calendar.current.dateComponents([.second], from: Date(), to: date1).second else {
return 0
}
return durationInSeconds
}
Function to generate date1 from 2018-10-09T18:19:00Z
func dateFromString(stringDate:String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale?
let date = dateFormatter.date(from: stringDate)
return date
}
The Date is always returning back an hour less than my current device time, so the calculation is not working as expected. If my current device time is 16:34 the Date() function returns it back as 15:34.
I have seen that Date() is returning back the time in UTC not based on my timezone.
At the moment if I pass in a Date 09/10/2018 14:25:00 and the current device time is 09/10/2018 14:20:00. I am expecting this function to return a value 300 which is 60 * 5 minute difference between two dates.
But I am getting back a value of 3900 which is because the date function returns the date as
09/10/2018 13:20:00 instead of 14:20
. So the duration will be 1 hour + the 300 second difference.
Including a sample output from Xcode console, my device time when I executed this code was 2018-10-09 17:56:28.565423
(lldb) po date1
▿ 2018-10-09 17:59:00 +0000
- timeIntervalSinceReferenceDate : 560800740.0
(lldb) po durationInSeconds
3731
(lldb) po Date()
▿ 2018-10-09 16:57:04 +0000
- timeIntervalSinceReferenceDate : 560797024.35021996
(lldb)
But I cant find a proper way to find the correct duration between two times based on my current time zone. How can I do it?
The issue is not with the Date() returning wrong time. Date() always returns the current time, which is not really based on your (any other) local timezone.
The problem seems to be with the dateFormatter that you are using to generate the Date object from the date string.
Please try using the following lines of code:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
// Not necessary as the dateFormatter would take the device's timeZone to be the default.
dateFormatter.timeZone = Calendar.current.timeZone
instead of:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
The problem with the latter is that, you are specifying 'Z' to be the zero-offset time zone (UTC). So, the difference of 1 hour from UTC in your device is causing this offset.
And, while passing in the date string, please make sure that you skip the 'Z' at the end (For example, it should be like 2018-10-09T18:19:00).
The updated code should work good for you, and return the expected difference in seconds.
Since you are using a string that represents the current time in your time zone, try this instead:
func getDurationInSeconds(date1: Date) -> Int {
return Int(-date1.timeIntervalSinceNow + TimeZone.current.daylightSavingTimeOffset(for: date1))
}
It uses this property and this method.
Or if you'd like to account for the time zone difference from UTC in dateFromString(stringDate:):
func getDurationInSeconds(date1: Date) -> Int {
return Int(-date1.timeIntervalSinceNow)
}
func dateFromString(stringDate:String) -> Date? {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
let date = dateFormatter.date(from: stringDate)! //I am force-unwrapping for brevity
let adjustedDate = date.addingTimeInterval(-TimeZone.current.daylightSavingTimeOffset(for: date))
return adjustedDate
}
Test
I am in a UTC + 1h timezone:
let str = "2018-10-09T19:50:00Z" //"2018-10-09T19:50:00Z"
let date1 = dateFromString(stringDate: str)! //"Oct 9, 2018 at 7:50 PM"
Date() //At the time of testing this it is "Oct 9, 2018 at 7:53 PM"
getDurationInSeconds(date1: date1) //213, which is 3 minutes and 33 seconds

Date Formatter failing on a correct date [duplicate]

I found that DateFormatter date(from:) method can't parse a couple of specific dates. Method returns nil for the 1st april of 1981-1984 years. Is it a bug of Foundation? What can we do to perform parsing of such dates?
Xcode 8.0, iOS SDK 10.0. Here is a screenshot of a short playground example:
This problem occurs if daylight saving time starts exactly on
midnight, as it was the case in Moscow in the years 1981–1984 (see for example Clock Changes in Moscow, Russia (Moskva)).
This was also observed in
Why does NSDateFormatter return nil date for these 4 time zones? and
Why NSDateFormatter is returning null for a 19/10/2014 in a Brazilian time zone?
For example, at midnight of April 1st 1984, the clocks were adjusted one hour forward, which means that the date "1984-04-01 00:00"
does not exist in that timezone:
let dFmt = DateFormatter()
dFmt.dateFormat = "yyyy-MM-dd"
dFmt.timeZone = TimeZone(identifier: "Europe/Moscow")
print(dFmt.date(from: "1984-04-01")) // nil
As a solution, you can tell the date formatter to be "lenient":
dFmt.isLenient = true
and then it will return the first valid date on that day:
dFmt.isLenient = true
if let date = dFmt.date(from: "1984-04-01") {
dFmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dFmt.string(from: date))
}
// 1984-04-01 01:00:00
A different solution
was given by rob mayoff, which is to make the date formatter use noon instead of midnight as the
default date. Here is a translation of rob's code from Objective-C to Swift:
let noon = DateComponents(calendar: dFmt.calendar, timeZone: dFmt.timeZone,
year: 2001, month: 1, day: 1, hour: 12, minute: 0, second: 0)
dFmt.defaultDate = noon.date
if let date = dFmt.date(from: "1984-04-01") {
dFmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
print(dFmt.string(from: date))
}
// 1984-04-01 12:00:00

Converting NSDate from UTC to local gives wrong result

I am creating an NSDate from components of hour and minute. It is in GMT and prints correctly as:
0001-01-01 07:30:00 +0000
I then want to convert this to my local timezone (CET), so I set up the NSDateFormatter like so:
formatter.timeZone = NSTimeZone.localTimeZone()
This prints (using .Longstyle):
08.13.00 GMT+0.43
This is wrong—it is supposed to be GMT+1. Printing the .localTimeZone() gives the correct offset:
Local Time Zone (Europe/Oslo (CET) offset 3600)
Edit1: By adding this extension(from an answer linked in comments) to NSDate, I can offset the timezone by hand. But then I need to set the NSDateFormatter timezone to GMT, which I don't think is right.
extension NSDate {
func toLocalTime() -> NSDate {
let timeZone = NSTimeZone.localTimeZone()
let seconds : NSTimeInterval = Double(timeZone.secondsFromGMTForDate(self))
let localDate = NSDate(timeInterval: seconds, sinceDate: self)
return localDate
}
}
Edit2: I made a test project. The expected output is for the time printed to match the offset in the timezone. Instead it adds 43 minutes.
func applicationDidFinishLaunching(aNotification: NSNotification) {
let calendar = NSCalendar.currentCalendar()
let realDateComponents = calendar.components([.Hour, .Minute], fromDate: NSDate())
guard let realDate = calendar.dateFromComponents(realDateComponents)
else{fatalError("Unable to get real date.")}
let formatter = NSDateFormatter()
formatter.timeStyle = .ShortStyle
print(realDate)
print(formatter.stringFromDate(realDate))
print(NSTimeZone.localTimeZone())
}
// OUTPUT
0001-01-01 21:03:00 +0000
21.46
Local Time Zone (Europe/Oslo (CET) offset 3600)
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).
Apparently you're creating the date from the .Hour and .Minute components, that sets the (indeterminate) year information to 01 (not 2001).
The point in time about 2000 years ago is a pretty large time interval which probably causes the weird behavior.