Get week number with week start day different than monday - IOS - ios

I want to get the week number of year associated with each date in IOS. I know I can get the ISO 8601 week number by using:
Calendar.current.component(.weekOfYear, from: Date())
But how to do it if the start day of a week could be any day of the week(like Sunday or Saturday)?

Just make your own Calendar with your own firstWeekday:
var calendar = Calendar.current
calendar.firstWeekday = someWeekdayYouLike
calendar.component(.weekOfYear, from: Date())
If you want to use the first weekday of some Locale, set the locale of the calendar instead:
var calendar = Calendar.current
calendar.locale = Locale(identifier: "en-gb")
print(calendar.firstWeekday) // 2
calendar.locale = Locale(identifier: "en-us")
print(calendar.firstWeekday) // 1

Related

Converting the string to date giving different format [duplicate]

This question already has answers here:
Getting date from [NSDate date] off by a few hours
(3 answers)
Closed 3 years ago.
Converting from string to date and date to string time format is changing the original data.
Tried with dateComponents as well by giving the hour and minute
var calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .hour], from: calFrom)
calendar.timeZone = .current
// Specify date components
var dateComponents:DateComponents = calendar.dateComponents([.year, .month, .day, .hour], from: Date())
dateComponents.year = components.year
dateComponents.month = components.month
dateComponents.day = components.day
dateComponents.hour = 08//Cutomised hour
dateComponents.minute = 34//Cutomised Minutes
// Create date from components
let someDateTime = calendar.date(from: dateComponents)
print(someDateTime!)
Actual Output:
2019-04-02 03:04:00 +0000
Expected Output:
2019-04-02 08:34:00 +0000
I tried with below code as well. Converting the date to String and manually appending the hour and minutes to the string and converting back to the date.
let calFrom = Date()
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
var calFromDate = formatter.string(from: calFrom)
calFromDate = calFromDate + " 09" + ":30"
print(calFromDate)
//Output 02/04/2019 09:30
formatter.dateFormat = "dd/MM/yyyy hh:mm"
formatter.locale = Locale.current// set locale to reliable US_POSIX
let date1 = formatter.date(from: calFromDate)
print(date1!)
Actual Output:
2019-04-02 04:00:00 +0000
Expected Output:
02/04/2019 09:30
How to get the exact time that has given in the output?
Date used to update the hour and minute components has UTC timezone so calendar should also have the same timeZone as below,
calendar.timeZone = TimeZone(abbreviation: "UTC")!

Swift DateFormatter - print week of year and year

I'm trying to print a given date in the format of "[week in a year] [year]" combination using a DateFormatter. I have given it a pattern of "w yyyy" but it returns an empty string.
let date = DateComponents(calendar: Calendar.current, year: 2018, month: 9, day: 28).date
let formatter = DateFormatter()
formatter.locale = Locale.current
formatter.setLocalizedDateFormatFromTemplate("w yyyy")
formatter.string(from: date!) // this returns ""
formatter.setLocalizedDateFormatFromTemplate("w")
formatter.string(from: date!) // this returns the correct number, like "36"
According to the Date Formatting Guide, iOS 5 uses version tr35-19. I assume that it hasn't changed since then.
In the unicode.org documentation, there is no special mention of how week of year is behaving in conjunction with a year format. What am I missing here?
EDIT I understand that I can use DateComponents to get the numbers and formatting them that way, but this question is more about why the format "w yyyy" is special.
Don't use setLocalizedDateFormatFromTemplate(). I'm not familiar with that method, but it sounds like it expects a pre-defined date string template, and your format string must not match any known templates. If you change your line
formatter.setLocalizedDateFormatFromTemplate("w yyyy")
to
formatter.dateFormat = "w yyyy"
It works as expected.
Edit:
It seems you should use:
formatter.dateFormat = "w Y"
y and yyyy will not give the correct results with certain dates.
Try this :
let date = Date()
let calendar = Calendar.current
let year = calendar.component(.year, from: date)
let month = calendar.component(.month, from: date)
let day = calendar.component(.day, from: date)
let weekOfYear = calendar.component(.weekOfYear, from: Date.init(timeIntervalSinceNow: 0))
OR
let date = Date()
let calendar = Calendar.current
let year = calendar.component(.year, from: date)
let month = calendar.component(.month, from: date)
let day = calendar.component(.day, from: date)
let weekOfYear = calendar.component(.weekOfYear, from: Date())

Weekday component issue

I'm trying to use weekday from calendar. I should receive Monday but somehow I'm receiving Tuesday. Any ideas why?
let date = Date(timeIntervalSince1970: 1519654139)
var calendar = Calendar(identifier: .gregorian)
calendar.locale = Locale(identifier: "en_US_POSIX")
calendar.timeZone = TimeZone(secondsFromGMT: 3600)!
let weekDayComponent = calendar.component(Calendar.Component.weekday, from: date)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEE EEEE"
print("Date formatter says it's " + dateFormatter.string(from: date))
print("Weekday component is \(weekDayComponent)")
Console output:
Date formatter says it's Mon Monday
Weekday component is 2
[EDIT]: Why I'm receiving 2, not 1? yes, value of calendar.firstWeekday is 1.
Week in gregorian calendar starts with Sunday, therefore it is a correct behavior, 2 is Monday. Documentation clearly states that:
Weekday units are the numbers 1 through n, where n is the number of days in the week. For example, in the Gregorian calendar, n is 7 and Sunday is represented by 1.

Swift 4 : Set Different Date and Time

I know how to get local date and time, but what I want to do is getting the date and time from different places. For example, I want to find out what the time and date is in New York. How can i solve this simple problem?
Here is my code for local date and time :
let date = NSDate()
let calendar = Calendar.current
let components = calendar.dateComponents([.hour, .minute, .month, .year, .day, .second, .weekOfMonth], from: date as Date)
let currentDate = calendar.date(from: components)
I searched about it here, but i didn't find what i want and I'm still looking for the date libaries. If you know any source or sample to redirect me, I really appreciate that.
There are several different concepts involved here, and we need to understand (almost) all of them to get this right...
1) a Date (NSDate as was, in Swift) is an absolute point in time - it's slightly mis-named, because it has nothing to do with an actual date like 13th November 2017, because to get to that we need to define ...
2) a Calendar, because 13th November 2017 in the western Gregorian calendar could also be 23rd Safar 1439 in the Islamic calendar, or the 24th of Heshvan 5778 in the Hebrew calendar, or some other things in the many other calendars that iOS & MacOS support;
3) in turn Calendar changes not only what values are returned in the DateComponents that we have to use to unpack a Date + Calendar into days, months, years & eras (e.g. BC/AD), or even week number, etc..., but also some calendars might not have the same components as others;
4) time-of-day (as you know) depends on TimeZone, so the same absolute time can be one of many different times "o'clock" depending on where you are. It may also (as you can see in the example below) change the date as well as the "o'clock". This of course could be automatic (where you are) or set by the programmer;
5) further, we have DateFormatter (which is a convenience that wraps up DateComponents), because 13th November 2017 could be represented as 13/11/17 or 11/13/17 depending on whether you are British or American. We may also wish to choose whether we use text or numeric months, and, if displaying times, whether we want 12 hour or 24 hour format - all of these are covered by DateFormatter, but text representation may be "13e Novembre 2017" if you are French, which introduces the notion of
6) Locale, which can be set, like TimeZone, as being default (as chosen when you set up the device) or specified by the programmer.
The code you posted won't work, because all it does is takes a Date, transforms it through a Calendar to DateComponents (all good so far), but then recreates a Date from the components - all you will get is the original Date - the same absolute point in time.
What I believe from the question and your answers to questions in the comments is that you want a function that takes an absolute time (eg "now") aka a Date and displays it in a specific TimeZone. This works:
func timeComponents(date: Date, timeZone: TimeZone) -> DateComponents {
var calendar = Calendar.current
calendar.timeZone = timeZone
return calendar.dateComponents([.hour, .minute, .month, .year, .day, .second, .weekOfMonth], from: date)
}
let absTime: Date = Date() // Now
let edinburgh = TimeZone(abbreviation: "GMT")!
let newYork = TimeZone(abbreviation: "EST")!
let ec = timeComponents(date: absTime, timeZone: edinburgh)
let nycc = timeComponents(date: absTime, timeZone: newYork)
print(ec)// year: 2017 month: 11 day: 14 hour: 0 minute: 44 second: 10 weekOfMonth: 3 isLeapMonth: false
print(nycc) // year: 2017 month: 11 day: 13 hour: 19 minute: 44 second: 10 weekOfMonth: 3 isLeapMonth: false
... which I think answers the minimum of your question, but to finesse it, we need to move from DateComponents to DateFormatter
func timeString(date: Date, timeZone: TimeZone, timeStyle: DateFormatter.Style) -> String {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = timeZone
dateFormatter.dateStyle = .none
dateFormatter.timeStyle = timeStyle
return dateFormatter.string(from: date)
}
let es = timeString(date: absTime, timeZone: edinburgh, timeStyle: .full)
let nycs = timeString(date: absTime, timeZone: newYork, timeStyle: .full)
print(es) // 12:44:10 AM Greenwich Mean Time
print(nycs) // 7:44:10 PM Eastern Standard Time
You can go on, and start to use Locale, if you want to internationalise your app, but I'l leave that as an exercise!
p.s. These are not all of the concepts - see here
p.p.s. See also this answer and this answer (neither duplicates)
If you just want to format the date to a string, consider using a DateFormatter instead:
let date = Date()
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "America/New_York")
formatter.dateStyle = .long
formatter.timeStyle = .long
formatter.string(from: date)
If you want to get the date components and process them, use the dateComponents(in:from:) method.
let components = Calendar.current.dateComponents(in: TimeZone(identifier: "America/New_York")!, from: date)
If you don't know the time zone of the place you are searching for, you can use the CoreLocation's CLGeocoder and search on an address string. Then you can get the timezone for that place and translate that into the time you're looking for:
let geocoder = CLGeocoder()
geocoder.geocodeAddressString("New York, New York") { (placemarks, error) in
guard error == nil else {
print("Error")
print(error!.localizedDescription)
return
}
guard let placemarks = placemarks,
let place = placemarks.first else {
print("No results")
return
}
if let timeZone = place.timeZone {
print("TimeZone: \(timeZone.identifier)")
// TimeZone: America/New_York
//Ignore the time zone offset from this one, it will be the difference between the current time and the new york time
let dateInNewYork = Date().addingTimeInterval(TimeInterval.init(timeZone.secondsFromGMT()))
print(dateInNewYork)
// 2017-11-13 15:03:05 +0000
//Or
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: timeZone.identifier)
formatter.dateStyle = .long
formatter.timeStyle = .long
let formattedDateInNewYork = formatter.string(from: Date())
print(formattedDateInNewYork)
// November 13, 2017 at 3:03:05 PM EST
//Or
let components = Calendar.current.dateComponents(in: TimeZone(identifier: timeZone.identifier)!, from: Date())
print(components.date!)
// 2017-11-13 20:03:05 +0000
}
}

day for Date() and Calendar.dateComponents don't match up

I'm trying to get the current date to print in a particular format (YYYYMMD) for AWS security credentials and I noticed that when I do Date(), the day is the 4th which is the correct value:
let date = Date()
print("\(date)") //2016-10-04 00:56:28 +0000
Now, I want to print the date in the format I desire so, but I keep getting the day value as the 3rd:
let calendar = Calendar.current
let date = Date()
let components = calendar.dateComponents([.day], from: date)
print("\(components.day)") //Optional(3)
S3 is expecting the date to be the 4th. How can I fix this?
It's because of time zone difference. date will return the UTC time and date but calendar will return the date and time based on your device's time zone. If you need the day number in UTC just set the time zone of the calendar object to UTC after you create it:
let calendar = Calendar.current
calendar.timeZone = TimeZone(abbreviation: "UTC")!
Now it will always match the value that is returned by Date()
When you print a date using
print("\(date)")
You get the date and time in UTC, which is probably not what you want.
If you want to display your date in your local time zone, create a date formatter and use that:
let dateFormatter = NSdateFormatter()
let dateFormatter.dateStyle = .medium
let dateFormatter.timeStyle = .medium
let dateString = dateFormatter.StringFromDate(date)
print ("date = \(dateString)")
If you do this a lot, you might want to create an extension on NSDate displayString so you can use that to display your dates without having to write additional code.

Resources