iOS - How to get date always at midnight? - ios

I am trying to get dates at midnight like, for example, 2019-08-01 00:00:00 +0000.
I have googled and tried to use all the possible answers that I found. But for some wired reason that I don't understand, none of them works.
I have used this code and I expect it to return 2019-08-08 00:00:00 +0000, it does 2019-08-08 22:00:00 +0000.
var calender = Calendar.current
calender.timeZone = Timezone.current
calender.startOfDay(for: Date()) // 2019-08-08 22:00:00 +0000
So what is the easiest way to find midnight date irrespective of the timezone? In other words, how to get midnight date according to the users timezone?

Your code is correct.
The last portion of the date string (+0000) represents the time zone. +0000 is Coordinated Universal Time (UTC), which includes the UK and western Africa. In other words, at midnight in the user's current time zone, it is 22:00 in London, England.
If you want to format your date to display the time stamp in the user's current time zone, you will have to use DateFormatter.
I live in Chicago, USA (-0500), and I've adjusted my timestamps accordingly
var calender = Calendar.current
calender.timeZone = TimeZone.current
let midnight = calender.startOfDay(for: Date()) // 2019-08-09 05:00:00 +0000
var dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone.current // Important!
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
dateFormatter.string(from: midnight) // 2019-08-09 00:00:00 -0500

Related

Time output not as expected when using iOS SDK DateFormatter on Date set to Jan 1, 1

I have a scenario where dates are being on a server without the day aspect and just the time is needed. Therefore the day element is being stripped away before uploading to the server. Development up to this point (Point 1 in code below) cannot be changed as it is coming from an external source that is already in production.
We are then facing an issue when outputting this time back to the user. The time varies by minutes in different locations, even in the same timezone. Please check the code with comments below.
//1.
//Taking a date with just hours and minutes as I don't need the date.
//The timezone set (Europe/Rome) is different from the machine (Europe/Malta)
//Issue below still occurs if we use the same timezone as the machine.
let date = Date(timeIntervalSinceReferenceDate: 1570168800) //Result: Oct 4, 2050 at 8:00 AM
var calendar = Calendar.current
calendar.timeZone = TimeZone(identifier: "Europe/Rome")!
let comps = calendar.dateComponents([.hour, .minute], from: date)
let strippedDate = calendar.date(from: comps)! //Result: Jan 1, 1 at 8:08 AM
//the date outputted is bypassing the timezone setting and using the machine timezone when stripping out the day
//and keeping hours and minutes alone
//2.
//Outputing the date back to the user in different timezone identifiers
//These timezone identiers are all in the same timezone
let dateFormatter = DateFormatter()
dateFormatter.timeStyle = .short;
dateFormatter.timeZone = TimeZone(identifier: "Europe/Paris")!
var formattedStart = dateFormatter.string(from: strippedDate) //Result: "7:19 AM"
dateFormatter.timeZone = TimeZone(identifier: "Europe/Rome")!
formattedStart = dateFormatter.string(from: strippedDate) //Result: "8:00 AM"
//This above appears correctly as it's coming from the same timezone that set up the starting date
dateFormatter.timeZone = TimeZone(identifier: "Europe/Malta")!
formattedStart = dateFormatter.string(from: strippedDate) //Result: "8:08 AM"
//The above appears the same as the stripped date which is the same as the machine used to create the stripped date
dateFormatter.timeZone = TimeZone(identifier: "Europe/Madrid")!
formattedStart = dateFormatter.string(from: strippedDate) //Result: "6:55 AM"
Referencing this answer, this issue is happening "Because at noon on November 18, 1883, the US and Canada railway companies began using a new, standard time system". Therefore since the date is being saved before this event, this might be the reason why we're getting varied minutes. However I still cannot find a solution to output the correct time.

How to identify the same time in both DST / non-DST for iPhone in Swift?

In swift, the current time Date() is retrieved from the system time of iPhone. Using DateFormatter() seems to work the same way with a given string. For example, using the following method, we can get the same result as calling Date() right when the iPhone time reaches 2018/04/01 02:00:00
let MY_DATE_STRING = "2018/04/01 02:00:00"
var resultTime: Date {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
formatter.timeZone = TimeZone.current
return formatter.date(from: MY_DATE_STRING)!
}
My question is, let's say, if 2018/04/01 2:00:00 is the end of daylight saving time, so the iPhone will have two 2am on that day -- one is with DST, while the other is not. These two times should have different UTC timestamp though. If currently the iPhone(or my self-defined MY_DATE_STRING) just enters the second 2am, which is a non-DST one, how could I set the TimeZone or other attributes so that the Date() or the given MY_DATE_STRING could generate the timestamp of second 2am instead of the first one?

convert date to specific timezone iOS swift [duplicate]

how can i return a NSDate in a predefined time zone from a string
let responseString = "2015-8-17 GMT+05:30"
var dFormatter = NSDateFormatter()
dFormatter.dateFormat = "yyyy-M-dd ZZZZ"
var serverTime = dFormatter.dateFromString(responseString)
println("NSDate : \(serverTime!)")
the above code returns the time as
2015-08-16 18:30:00 +0000
The date format has to be assigned to the dateFormat property of the date formatter instead.
let date = NSDate.date()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let str = dateFormatter.stringFromDate(date)
println(str)
This prints the date using the default time zone on the device. Only if you want the output according to a different time zone then you would add for example
Swift 3.*
dateFormatter.timeZone = NSTimeZone(name: "UTC")
Swift 4.*
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
also refer link http://www.brianjcoleman.com/tutorial-nsdate-in-swift/
how can i return a NSDate in a predefined time zone?
You can't.
An instance of NSDate does not carry any information about timezone or calendar. It just simply identifies one point in universal time.
You can interpret this NSDate object in whatever calendar you want. Swift's string interpolation (the last line of your example code) uses an NSDateFormatter that uses UTC (that's the "+0000" in the output).
If you want the NSDate's value as a string in the current user's calendar you have to explicitly set up a date formatter for that.
Swift 4.0
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
If you always have the same time zone for the input string, you can create two date formatters to output the local time zone (or a specified one):
let timeFormatterGet = DateFormatter()
timeFormatterGet.dateFormat = "h:mm a"
timeFormatterGet.timeZone = TimeZone(abbreviation: "PST")
let timeFormatterPrint = DateFormatter()
timeFormatterPrint.dateFormat = "h:mm a"
// timeFormatterPrint.timeZone = TimeZone(abbreviation: "EST") // if you want to specify timezone for output, otherwise leave this line blank and it will default to devices timezone
if let date = timeFormatterGet.date(from: "3:30 PM") {
print(timeFormatterPrint.string(from: date)). // "6:30 PM" if device in EST
} else {
print("There was an error decoding the string")
}
The number 1 means 1 regardless of language. Yet in English it's spelled as one, in Spanish it's una, in Arabic it wahid, etc.
Similarly 123982373 seconds pass 1970 is going to reflect differently in different timezones or calendar formats, but's all still 123982373 seconds passed 1970
The difference between 3 seconds and 7 seconds is 4 seconds. That doesn't require a calendar. Neither you need a calendar/timezone to know the difference in time between these two Epoch times 1585420200 and 1584729000
Dates are just a timeInterval from January 1, 1970 (midnight UTC/GMT). Dates also happen to have a string representation.
Repeating Nikolia's answer, Swift's default string interpolation (2015-08-16 18:30:00 +0000) uses a DateFormatter that uses UTC (that's the "+0000" in the output).
Calendars with the use of timezones give us a contextual representation that is just easier to understand than trying to calculate the difference between two gigantic numbers.
Meaning a single date (think of a single timeInterval since 1970) will have a different string interpretations per calendar. On top of that a calendar will itself vary based on time zones
I highly recommend that you go and play around with this Epoch converter site and see how selecting a different timezone will cause the string representations for the same moment/date/timeInterval to change
I also recommend to see this answer. Mainly this part:
Timezone is just an amendment to the timestamp string, it's not considered by the date formatter.
To consider the time zone you have to set the timeZone of the formatter
dateFormatter.timeZone = TimeZone(secondsFromGMT: -14400)

DateComponents giving wrong date

I am trying to convert today's date using DateComponents:
let calendar = Calendar.current
//add today's date
var todayDate = Date()
var dateComponents = calendar.dateComponents([.day, .month, .year], from: todayDate)
dateComponents.timeZone = TimeZone.current
todayDate = calendar.date(from: dateComponents)!
While debugging I found that after declaring todayDate, its value was 2016-11-11 07:44:44 +0000. After using dateComponents, the value changed to 2016-11-10 18:30:00 +0000. Whereas according to my location, the day should be 11th November, and the time should be somewhere between 1 or 2 PM. Why is this happening?
You haven't specified a timezone, nor hours minutes and seconds in your components. So, all these values are assumed to be zero. The resulting time is at midnight GMT on the year, month and day that you specified.
When you printed the result, you specified your current timezone, which appears to be 5h 30m different.
I'm guessing you are in India.

NSDate being interpreted several hours off (minutes and day working fine)

I am updating the question to be more precise, thank you for the feedback already.
So I am setting a cell for a tableview and displaying the time of the event on the cell itself and to do so am using Parse. The date is downloading correctly from parse as evidenced by the first println, but when I make the label text equal the dateToString of the when date (which is the one from parse) it throws it off by several hours for some reason. The simulator however displays the right time on the status bar and the phones gps is set to EST as well... So I am very confused.
Here is the entire function:
func configureCell(object : PFObject)-> Void {
eventNameText.text = (object.objectForKey("name") as? String)!
var when = (object.objectForKey("when") as? NSDate)!
numEchoesText.text = String(stringInterpolationSegment: object.objectForKey("numEchoes")!)
println(when)
var formatter = NSDateFormatter()
formatter.dateFormat = "EEEE, h:mm a"
parseid = object.objectId!
if (contains(echoes, parseid)) {
echoImage.setImage(imageEchoed, forState: .Normal)
}
else {
echoImage.setImage(imageUnechoed, forState: .Normal)
}
var now = NSDate()
whenText.text = formatter.stringFromDate(when)
println(formatter.stringFromDate(now))
println(formatter.stringFromDate(when))
self.object = object
}
And here is the result:
2015-05-31 23:43:00 +0000
Tuesday, 9:30 AM
Sunday, 7:43 PM
Please note that the first time is correct but the datetostring is interpreting it as the third line. I added a middle println to display the current date in order to show that the datetostring is working correctly for the now date.
Thanks in advance for any help!!
Edit: updated answer based on new details.
Your trouble is because of the timezone. NSDate does not store any time zone information.
println(when)
--> 2015-05-31 23:43:00 +0000 // notice the timezone is 0000 / GMT
Adding a timezone to the NSDateFormatter will help you see what's going on behind the scene:
var formatter = NSDateFormatter()
formatter.dateFormat = "EEEE, h:mm a z"
println(formatter.stringFromDate(when))
--> Sunday, 7:43 PM xyz // Depends on the timezone on your device
The two represents the same point in time, but expressed in different timezones. To solve this, you need to set the timezone of the formatter to GMT:
var formatter = NSDateFormatter()
formatter.dateFormat = "EEEE, h:mm a z"
formatter.timeZone = NSTimeZone.init(name:"GMT")
println(formatter.stringFromDate(when))
--> Sunday, 11:43 PM GMT
You can remove the timezone identifier now that you get it correct. Date & time manipulation in Cocoa / iOS are a lot more complicated than other languages (Java, C#, Javascript, etc.) Sometimes I wish Apple just created a NSDate class with methods to add & subtract date/time components, switch timezone, etc. I can dream on.
Take a look at NSDateFormatter and how it works. If I do understand your question clearly, I think this should work.
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm"
dateFormatter.stringFromDate(parseDateObject)
2015-05-31 23:43:00 +0000 means "the 31st of May 2015 at 23:43:00 at +0000 from UTC".
According to your question "The simulator however displays the right time on the status bar and the phones gps is set to EST".
If you convert that date from UTC to EST you get "Sunday, 7:43 PM".
Your NSDate is therefore being interpreted perfectly.
Making reasonable assumptions about the Parse API, it looks like somebody has imported your data incorrectly.

Resources