2016-11-08 3 views
3

Мне нужно сделать функцию для подсчета числа недель данного года в быстром, в соответствии с ISO-недельной системой (ISO8601). Мне нужен номер как Int. Сначала я решил, что мне нужно сделать NSDate 31 декабря и спросить, на какой неделе это, тогда я понял, что иногда 31 декабря на неделе 1 следующего года (например, 31 декабря 2014 года) Кто-нибудь знает способ сделать это ?Получить количество недель для данного ISO 8601 календарного года

Я попытался

var calendarr = NSCalendar(calendarIdentifier: NSCalendar.Identifier.ISO8601)! 
var monday = "01-01-2005" 

var dateFormatter = DateFormatter() 
dateFormatter.dateFormat = "dd/MM/yyyy" 
var datumet = dateFormatter.date(from: monday) 
var weekRange = calendarr.range(of: .weekOfYear, in: .year, for: datumet!) 
var weeksCount = weekRange.length 

print("this many weeks", weeksCount) 

Но это дает мне 53 недель, независимо от того, в каком году я поставил в качестве эталона 2004 было 53 недель и 2005 было 52 недель

ответ

1

Простая формула для определения количества недель в календаря ISO год можно найти в Long and Short ISO Calendar Years:

по ISO календарный год у длительно (содержит 53 недель), если:
- р (у) по модулю 7 = 4
или если:
- р (у-1) по модулю 7 = 3
с:
- р (у) = у + пол (у/4) - пол (у/100) + пол (y/400)

Обратите внимание, что версия в Wikipedia: Weeks per year кажется , чтобы иметь небольшую ошибку: «Если p (год) = 5« должно быть », если p (год) = 4".

Это реализация в Swift:

func weeks(in year: Int) -> Int { 
    func p(_ year: Int) -> Int { 
     return (year + year/4 - year/100 + year/400) % 7 
    } 
    return (p(year) == 4 || p(year-1) == 3) ? 53 : 52 
} 

Тест:

print(weeks(in: 2015)) // 53 
print(weeks(in: 2016)) // 52 

let longYears = (2000...2100).filter({ weeks(in: $0) == 53 }) 
print(longYears) 
// [2004, 2009, 2015, 2020, 2026, 2032, 2037, 2043, 2048, 2054, 2060, 2065, 2071, 2076, 2082, 2088, 2093, 2099] 

, который совпадает с перечнем, приводимым в статье Википедии.


Re правки: Ваша попытка код почти правильно. Как @vadian уже говорилось в комментарии, он должен быть

let weekRange = calendarr.range(of: .weekOfYear, in: .yearForWeekOfYear, for: datumet!) 

Кроме того, 1 января может упасть в предыдущего года ISO (например, в течение 2016 года). Выбор любого дня с 4 января по 28 декабря в данном году разрешил бы эту проблему.

С некоторыми дополнительными упрощениями, что дает следующие метод (на основе Kevin Sabbe's approach):

func weeks(in year: Int) -> Int { 
    let cal = Calendar(identifier: .iso8601) 
    let date = DateComponents(calendar: cal, year: year, month: 2, day: 1).date! 
    let weeksRange = cal.range(of: .weekOfYear, in: .yearForWeekOfYear, for: date)! 
    return weeksRange.count 
} 

который производит те же результаты, что и выше функция.

+1

Это просто великолепно! Спасибо! –

2

Работа для Swift 3:.

let weekRange = NSCalendar.current.range(of: .weekOfYear, in: .yearForWeekOfYear, for: Date()) 

print("\(weekRange?.count)") 

Вы должны указать год в Дате(), и он даст вам количество недель в течение всего года.

Надеюсь, это поможет!

+0

Для системы * ISO-week * вам нужен календарь 'NSCalendar'' ISO8601' и блок '.yearForWeekOfYear' – vadian

+0

Vadian, не могли бы вы посмотреть код, который я добавил в свой вопрос, и показать мне, где. yearForWeekOfYear должно быть. Я пробовал как в слоте «of:», так и в слоте «in:» недели. Range-line –

+0

@KlasZetterlund: он должен быть «in: .yearForWeekOfYear». Кроме того, вы не должны выбирать 1 января как дату, потому что это может упасть в предыдущий год ISO. С '01-02-yyyy' он должен работать. –

Смежные вопросы