I'm trying to find the first day of the month. There have been different solutions posted here on SO (e.g. this)
When analyzing them it seems like the day component is being ignored.
Instead of returning the first day of the month
Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!
it returns the current day but changes the month:
(lldb) po Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!
▿ 2019-02-28 23:00:00 +0000
- timeIntervalSinceReferenceDate : 573087600.0
(lldb) po self
▿ 2019-03-28 01:09:17 +0000
- timeIntervalSinceReferenceDate : 575428157.663583
I've also looked into setting the components by hand:
var components = Calendar.current.dateComponents([.year, .month, .day], from: self)
components.setValue(1, for: .day)
let value = Calendar.current.date(from: components)!
which results in the same:
(lldb) po value
▿ 2019-02-28 23:00:00 +0000
- timeIntervalSinceReferenceDate : 573087600.0
Am I doing something wrong? Or is this a bug in Calendar?
Apple Swift version 5.0.1 (swiftlang-1001.0.82.4 clang-1001.0.46.5)
Target: x86_64-apple-darwin18.6.0
Oh in case this is interesting I'm developing for macOS but as far as I can see, this API is not influenced by Catalina.
Your code is fine. You have a date that is in March 2019. You create a new date that is March 1, 2019 at midnight local time. All good so far.
The only issue is your misunderstanding of the output of printing that date. The date is printed in the debugger in UTC time. That's what the +0000 means - UTC time. You must live in the UTC+1 timezone.
So March 1, 2019 at midnight your local time is the same as February 28, 2019 at 23:00 UTC. It's the same moment in time, just displayed in a different timezone.
In short, your code is fine.
Related
I am trying to implement a simple countdown timer in my test app.
I have two dates:
fromDate - which is current time that I get by Date(), e.g. 2021-08-27 11:07:34 +0000
toDate - is a future date, e.g. 2021-11-17 01:00:00 +0000
I am using DateComponents to get back the difference in days, hours, minutes and seconds.
let components = Calendar.current.dateComponents([.day, .hour, .minute, .second],
from: fromDate,
to: toDate)
Its returning me back the values for days hours minute and second 81, 12, 52, 25
The values for day, minute and second are correct, but the hour is 1 hour less.
I suspect daylight timing has to do something with this but I cannot find anything that can help here.
Kindly help me what I am doing wrong as I have tried many things in past few days but nothing seems to work
I was able to reproduce the behaviour by using:
let from = Date(timeIntervalSince1970: 1630062455)
print(from) // 2021-08-27 11:07:35 +0000
let to = Date(timeIntervalSince1970: 1637110800)
print(to) // 2021-11-17 01:00:00 +0000
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "Europe/London")!
let comp = calendar.dateComponents([.day, .hour, .minute, .second], from: from, to: to)
print(comp.day!, comp.hour!, comp.minute!, comp.second!)
The reason why this happens is because when doing dateComponents(_:from:to:), Calendar takes into account its timezone. After all, without a timezone, (almost) no date components would make sense - you would not be able to tell what hour a Date is, for example. A Date just represents an instant in time/n seconds since the epoch.
(In the case of Calendar.current, the timezone it uses is TimeZone.current)
Europe/London would go out of DST at some point between from and to. This means the calendar would calculate the difference in date components between:
from: 2021-08-27 12:07:35
to: 2021-11-17 01:00:00
Notice that the first time is 12:07:35, rather than 11:07:35. This is because at 2021-08-27 11:07:35 +0000, the local date time at Europe/London really is 2021-08-27 12:07:35.
To get your desired output, just change the calendar's timeZone to UTC:
var calendar = Calendar.current
calendar.timeZone = TimeZone(identifier: "UTC")!
let comp = calendar.dateComponents([.day, .hour, .minute, .second], from: from, to: to)
I am trying to get a Date object for the next occurring future time where the hour in UTC time is 18. However my code doesn't work as expected. I have the following:
let dateComponents = DateComponents(timeZone: TimeZone(abbreviation: "GMT"), hour: 18)
let date = Calendar.current.nextDate(after: Date(), matching: dateComponents, matchingPolicy: .nextTime)
print(date)
The problem is that this results in 2019-02-09 23:00:00 +0000
The date is for the next occurring time where the hour is 18 in EST.
I would have expected, since the the dateComponents has the timezone set to UTC and the hour to 18, that the date would be 2019-02-09 18:00:00 +0000. Furthermore, changing the timezone seems to have no effect on the nextDate found.
Why doesn't the nextDate function respect the timezone set in the dateComponents passed to it?
It looks like the timezone in DateComponents is ignored.
However when you set the timezone in a new calendar you get correct results.
let dateComponents = DateComponents(hour: 18)
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
let date = calendar.nextDate(after: Date(), matching: dateComponents, matchingPolicy: .nextTime)
print(date) // Optional(2020-09-29 18:00:00 +0000)
I live in GMT time, and running this in a playground produces the expected result you are looking for. You are setting the time zone of your date component, but I would imagine your own calendar (Calendar.current) is set to EST. You would need to account for the offset in EST vs GMT for your required result
I'm trying to do some date manipulation with Swift and I'm getting an unexpected result. The webservice will pass in a string date, and then I want to get that month and the previous month. I'm using this code (with input grab and such removed):
import Foundation
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(identifier: "America/New_York")
formatter.dateFormat = "yyyy-MM-dd"
let date = formatter.date(from: "2018-12-01")!
let prev = Calendar.current.date(byAdding: .month, value: -1, to: date)!
formatter.string(from: date)
formatter.string(from: prev)
So I've got a valid date, and then I subtract a month from it. The first formatted date shows my expected 2018-12-01 but then on the second line, instead of saying 2018-11-01 it says 2018-10-31.
I'm in PST, which is of course 3 hours ahead of EST. If I add 3 hours I'd get the expected strings. However, since both the input and the output strings were done with a formatter using the timezone, why don't I get the expected output?
The problem is that Calendar.current is in a different timezone (for you) than the formatter.
So date is December 1, 2018 at midnight New York time. But that is November 30, 2018 at 9pm local time (PST) for you.
When you subtract one month it is done in local time (Calendar.current) so you get October 30, 2018 at 9pm. Then you format that date to New York time and it results in October 31, 2018 at midnight.
To get the proper results you want a Calendar in the same timezone as the formatter:
var cal = Calendar(identifier: Calendar.current.identifier)
cal.timeZone = formatter.timeZone
let prev = cal.date(byAdding: .month, value: -1, to: date)!
This will give the expected result.
This question already has answers here:
NSDate() or Date() shows the wrong time
(2 answers)
Closed 4 years ago.
I created an object that has a creation date property. The date property is calculated by using the Date() function, for getting the current date and time.
The date is correct but the time is 3 hours behind the clock of the simulator. How can I fix this?
The system displays the current date / time of UTC/GMT.
To get time/date for local time zone. use following code:
let currentDate = Date()
//7/29/18, 9:09 PM
print (DateFormatter.localizedString(
from: currentDate,
dateStyle: .short,
timeStyle: .short))
//Sunday, July 29, 2018 at 9:09:27 PM India Standard Time
print (DateFormatter.localizedString(
from: currentDate,
dateStyle: .full,
timeStyle: .full))
//Jul 29, 2018 at 9:09:27 PM
print (DateFormatter.localizedString(
from: currentDate,
dateStyle: .medium,
timeStyle: .medium))
Above code is tested in India at 09:09 PM on 29th July 2018.
I am trying to get date components from a date value from an API endpoint. I need to preserve the date values as they are already adjusted for time zone. Unfortunately, I have no control over how the API returns a date value.
When I get the date value (sessionTime) from the API, it is returned as follows:
2017-12-05 08:00:00 +0000
I need to set up a local notification based on that time, however, when I try to extract components from that date object with the following code:
let notifyTime = Calendar.current.dateComponents(
[.year, .month, .day, .hour, .minute, .second], from: sessionTime)
I get this:
year: 2017 month: 12 day: 5 hour: 2 minute: 0 second: 0 isLeapMonth: false
I am six hours from GMT so it is obvious what is going on, but I wish I could prevent it and extract the date components exactly as they are. The desired output would be:
year: 2017 month: 12 day: 5 hour: 8 minute: 0 second: 0 isLeapMonth: false
Can anyone help? Thanks!
You can specify the timeZone that DateComponents uses.
Like this:
let notifyTime = Calendar.current.dateComponents(in: TimeZone.current, from: sessionTime)