получить NSDate сегодня, вчера, на этой неделе, на прошлой неделе, в этом месяце, переменные за последний месяц

Я пытаюсь получить NSDate сегодня, вчера, на этой неделе, на прошлой неделе, в этом месяце, переменные прошлого месяца, готовые для сравнения для заголовков, которые будут добавлены в заголовок UITableView titleForHeaderInSection

То, что я хочу, сделано вручную в приведенном ниже коде на дату 2009-12-11.

 NSDate *today = [NSDate dateWithString:@"2009-12-11 00:00:00 +0000"];
 NSDate *yesterday = [NSDate dateWithString:@"2009-12-10 00:00:00 +0000"];
 NSDate *thisWeek = [NSDate dateWithString:@"2009-12-06 00:00:00 +0000"];
 NSDate *lastWeek = [NSDate dateWithString:@"2009-11-30 00:00:00 +0000"];
 NSDate *thisMonth = [NSDate dateWithString:@"2009-12-01 00:00:00 +0000"];
 NSDate *lastMonth = [NSDate dateWithString:@"2009-11-01 00:00:00 +0000"];

person hasnat    schedule 11.12.2009    source источник


Ответы (11)


Адаптировано из Руководства по программированию даты и времени:

// Right now, you can remove the seconds into the day if you want
NSDate *today = [NSDate date];

// All intervals taken from Google
NSDate *yesterday = [today dateByAddingTimeInterval: -86400.0];
NSDate *thisWeek  = [today dateByAddingTimeInterval: -604800.0];
NSDate *lastWeek  = [today dateByAddingTimeInterval: -1209600.0];

// To get the correct number of seconds in each month use NSCalendar
NSDate *thisMonth = [today dateByAddingTimeInterval: -2629743.83];
NSDate *lastMonth = [today dateByAddingTimeInterval: -5259487.66];

Если вам нужно точное количество дней в зависимости от месяца, вам следует использовать NSCalendar .

person Ben S    schedule 11.12.2009
comment
извините, если вы не поняли, что раздаете последние 7 дней на этой неделе, что в некотором смысле правильно, но мне нужна настоящая неделя, спасибо за предложение NSCalendar - person hasnat; 11.12.2009
comment
Да, если вы хотите, чтобы текущая неделя начиналась с субботы, вам нужно использовать NSCalendar. - person Ben S; 11.12.2009
comment
Фиксированные константы для времени ПЛОХО ПЛОХО ПЛОХО. А как насчет високосных дней или високосных секунд? Используйте NSDateComponents, иначе вы БУДЕТЕ столкнуться с некоторыми очень неприятными и трудными для отладки проблемами, когда ваши отметки даты начнут не совпадать. - person Kendall Helmstetter Gelner; 12.12.2009
comment
На самом деле это не так уж и плохо, если вам просто нужны посты примерно за последнюю неделю или что-то еще. Я указал, что OP должен использовать NSCalendar, если требуется точность. - person Ben S; 12.12.2009
comment
Фиксированные константы действительно подходят для подсчета дней: каждый день составляет 86400 секунд. Просто дополнительные секунды занимают вдвое больше - день с дополнительной секундой по-прежнему имеет 86400 «секунд». Что касается месяцев ... да, держитесь подальше :) - person Chris; 19.09.2011
comment
addTimeInterval устарел. Этот метод был заменен на dateByAddingTimeInterval: - person shawnwall; 08.02.2012
comment
@shawnwall Спасибо! Я обновил свой ответ, чтобы использовать новый метод. - person Ben S; 08.02.2012
comment
ПЛОХО ПЛОХО ПЛОХО Из-за того, что сказал Кендалл Хельмштеттер. Посмотрите сессию 244 WWDC 2012 (Советы и уловки по интернационализации) для получения дополнительной информации. - person 3lvis; 23.08.2012
comment
@Chris, кроме случаев, когда дни не 86400 секунд. А как насчет перехода на летнее время? Это звучит незначительно, но на самом деле это может привести вас к супер-грубым ошибкам, которые возникают из ниоткуда, когда наступает переход на летнее время, и вы не забыли это принять во внимание. - person jpswain; 13.03.2013
comment
Если вы просто хотите вернуться, скажем, примерно на 7 дней, вы можете просто вычесть время, если вы хотите вернуться к «понедельнику» этой недели, используйте NSCalendar. Есть варианты использования для обоих сценариев. - person Johnny Rockex; 02.09.2016

Возможно, это лучший способ написать это, но вот что я придумал по предложению Бена NSCalendar и работал оттуда с NSDateComponents

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond ) fromDate:[[NSDate alloc] init]];

[components setHour:-[components hour]];
[components setMinute:-[components minute]];
[components setSecond:-[components second]];
NSDate *today = [cal dateByAddingComponents:components toDate:[[NSDate alloc] init] options:0]; //This variable should now be pointing at a date object that is the start of today (midnight);

[components setHour:-24];
[components setMinute:0];
[components setSecond:0];
NSDate *yesterday = [cal dateByAddingComponents:components toDate: today options:0];

components = [cal components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:[[NSDate alloc] init]];

[components setDay:([components day] - ([components weekday] - 1))]; 
NSDate *thisWeek  = [cal dateFromComponents:components];

[components setDay:([components day] - 7)];
NSDate *lastWeek  = [cal dateFromComponents:components];

[components setDay:([components day] - ([components day] -1))]; 
NSDate *thisMonth = [cal dateFromComponents:components];

[components setMonth:([components month] - 1)]; 
NSDate *lastMonth = [cal dateFromComponents:components];

NSLog(@"today=%@",today);
NSLog(@"yesterday=%@",yesterday);
NSLog(@"thisWeek=%@",thisWeek);
NSLog(@"lastWeek=%@",lastWeek);
NSLog(@"thisMonth=%@",thisMonth);
NSLog(@"lastMonth=%@",lastMonth);
person hasnat    schedule 11.12.2009
comment
Вы полностью теряете память этими fromDate:[[NSDate alloc] init] битами. - person Shaggy Frog; 23.12.2009
comment
@ Shaggy Frog: Я думаю, он предполагает, что ARC включен ...;) - person orj; 13.03.2012
comment
Этот код работает некорректно. Он не принимает во внимание доли секунды, которые являются частью даты ввода. То есть дата может иметь 30,1234 секунды, а NSDateComponents имеет только 30 секунд в качестве значения секунд, поэтому вычитание 30 секунд из NSDate оставляет вам 0,1234 секунды после полуночи. Кроме того, в некоторые дни больше (или меньше) 24 часов (летнее время), поэтому для получения вчерашней даты действительно нужно использовать [components setDay: -1], а не [components setHour: -24]. - person orj; 13.03.2012
comment
@orj К вашему сведению, ARC вышла спустя много лет после того, как был опубликован этот ответ - person Shaggy Frog; 13.03.2012
comment
@orj Кроме того, при переходе на летнее время вычитание часов не дает полуночи. -1. Этот код не стоит 35 голосов. - person Nikolai Ruhe; 16.05.2013

NSDateComponents приятно получить сегодня:

NSCalendar *cal = [NSCalendar currentCalendar];

NSDate *date = [NSDate date];
NSDateComponents *comps = [cal components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) 
                                                          fromDate:date];
NSDate *today = [cal dateFromComponents:comps];

Это создает NSDate только с годом, месяцем и датой:

(gdb) po today
2010-06-22 00:00:00 +0200

Чтобы получить вчерашний день и т. Д., Вы можете рассчитать его с помощью NSDateComponents:

NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:-1];
NSDate *yesterday = [cal dateByAddingComponents:components toDate:today options:0];
person Christian Beer    schedule 22.06.2010
comment
Разве вам не нужно включать компонент эпохи? - person Chris Page; 23.10.2011
comment
Хороший. Использовал это для вычисления даты на 8 лет назад, и это прекрасно работает. Просто нужно исправить утечку здесь: [[NSDateComponents alloc] init]; - person Craig B; 14.11.2011
comment
@CraigB, спасибо. Это не полный пример. Упускаем из виду очевидное управление памятью как проблему для читателя;) - person Christian Beer; 14.11.2011
comment
@ChrisPage компонент эпохи? Зачем? - person Christian Beer; 14.11.2011
comment
@ChristianBeer Я уверен, что нужно учитывать все компоненты, разрешение которых превышает желаемое. Я считаю, что (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) должно быть (NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit). - person Chris Page; 05.01.2012

Swift 4.2

let today = Date()
let yesterday = today.addingTimeInterval(-86400.0)
let thisWeek = today.addingTimeInterval(-604800.0)
let lastWeek = today.addingTimeInterval(-1209600.0)

let thisMonth = today.addingTimeInterval(-2629743.83)
let lastMonth = today.addingTimeInterval(-5259487.66)

// components of the date
let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
let components = calendar.dateComponents([.year, .month, .day], from: today)
let (year, month, day) = (components.year, components.month, components.day)

Обратите внимание, что компоненты даты не являются обязательными.

person gokhanakkurt    schedule 04.01.2016
comment
@fengd хорошо, сегодня, 27 июня 2016 года, в час ночи дата будет 28 июня 2016 года, и если я вычту 24 часа, дата будет 27 июня 01:00. Что я упустил? - person gokhanakkurt; 27.06.2016
comment
прости, @gokhanakkurt. Думаю, у меня была какая-то икота. ваш ответ правильный - person fengd; 28.06.2016

Другие ответы просто не сработали для меня (возможно, из-за моего часового пояса). Вот как я это делаю:

- (BOOL)isOnThisWeek:(NSDate *)dateToCompare
{
    NSCalendar * calendar = [NSCalendar currentCalendar];
    NSDate     * today    = [NSDate date];

    int todaysWeek        = [[calendar components: NSWeekCalendarUnit fromDate:today] week];
    int dateToCompareWeek = [[calendar components: NSWeekCalendarUnit fromDate:dateToCompare] week];

    int todaysYear         = [[calendar components:NSYearCalendarUnit fromDate:today] year];
    int dateToCompareYear  = [[calendar components:NSYearCalendarUnit fromDate:dateToCompare] year];

    if (todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear) {
        return YES;
    }

    return NO;
}
person Lucas    schedule 15.10.2012

Если вы используете iOS 10+ или MacOS 10.12+, вы можете использовать эти два Calendar метода, чтобы сделать это правильно.

  • func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool = default) -> Date? (документы)
  • func dateInterval(of component: Calendar.Component, for date: Date) -> DateInterval? (документы)

Вот пример того, как использовать эти методы в Swift 3 вместе с выводом игровых площадок в моем часовом поясе.

let calendar = Calendar.current
let now = Date()
// => "Apr 28, 2017, 3:33 PM"

let yesterday = calendar.date(byAdding: .day, value: -1, to: now)
// => "Apr 29, 2017, 3:33 PM"
let yesterdayStartOfDay = calendar.startOfDay(for: yesterday!)
// => ""Apr 29, 2017, 12:00 AM"

let thisWeekInterval = calendar.dateInterval(of: .weekOfYear, for: now)
// => 2017-04-23 04:00:00 +0000 to 2017-04-30 04:00:00 +0000

let thisMonthInterval = calendar.dateInterval(of: .month, for: now)
// => 2017-04-01 04:00:00 +0000 to 2017-05-01 04:00:00 +0000

let aDateInLastWeek = calendar.date(byAdding: .weekOfYear, value: -1, to: now)
let lastWeekInterval = calendar.dateInterval(of: .weekOfYear, for: aDateInLastWeek!)
// => 2017-04-16 04:00:00 +0000 to 2017-04-23 04:00:00 +0000

let aDateInLastMonth = calendar.date(byAdding: .month, value: -1, to: now)
let lastMonthInterval = calendar.dateInterval(of: .weekOfYear, for: aDateInLastMonth!)
// => 2017-03-26 04:00:00 +0000 to 2017-04-02 04:00:00 +0000

Бонус: вы можете использовать DateIntervals, чтобы проверить, попадает ли дата в этот диапазон. Продолжая сверху:

thisWeekInterval!.contains(now)
// => true
lastMonthInterval!.contains(now)
// => false
person yood    schedule 28.04.2017
comment
Почему yesterday говорит 29 апреля, а now говорит 28 апреля? - person Juan Boero; 10.07.2020

Мне очень нравится объект THCalendarInfo, содержащийся в этом проекте:

http://github.com/jaredholdcroft/kcalendar

Не могу найти оригинал. Используя этот объект, вы можете перейти к предыдущему дню, началу недели, началу месяца, получить день недели, день месяца ... и т. Д. И т. Д.

person Kendall Helmstetter Gelner    schedule 11.12.2009

Это для проверки, дата в этом месяце или нет

func isOnThisMonth(dateToCompare: NSDate) -> Bool {
    let calendar: NSCalendar = NSCalendar.currentCalendar()
    let today: NSDate = NSDate()
    let todaysWeek: Int = calendar.components(NSCalendarUnit.Month, fromDate: today).month
    let dateToCompareWeek: Int = calendar.components(.Month, fromDate: dateToCompare).month
    let todaysYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: today).year
    let dateToCompareYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: dateToCompare).year
    if todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear {
        return true
    }
    return false
}

А во-вторых, меняет только тип CalendarUnit для слабых вроде этого

func isOnThisWeek(dateToCompare: NSDate) -> Bool {
    let calendar: NSCalendar = NSCalendar.currentCalendar()
    let today: NSDate = NSDate()
    let todaysWeek: Int = calendar.components(NSCalendarUnit.Weekday, fromDate: today).weekday
    let dateToCompareWeek: Int = calendar.components(.Weekday, fromDate: dateToCompare).weekday
    let todaysYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: today).year
    let dateToCompareYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: dateToCompare).year
    if todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear {
        return true
    }
    return false
}

Надеюсь, это кому-то поможет. Спасибо.

person Ilesh P    schedule 01.06.2016

Я уже ответил на аналогичный вопрос , и вот почему мой ответ лучше:

  • Swift 3!
  • Использует DateFormatter «Вчера» и «Сегодня». Это уже переведено Apple, что экономит вам работу!
  • Использует уже переведенную строку "1 неделя" DateComponentsFormatter. (Опять меньше работы, любезно предоставлено Apple.) Все, что вам нужно сделать, это перевести строку «% @ ago». ????
  • В других ответах неправильно вычисляется время, когда день переключается с «сегодня» на «вчера» и т.д. > причины. Кроме того, в других ответах используется текущая дата / время, тогда как они должны использовать дату / время конца текущего дня.
  • Использует autoupdatingCurrent для календаря и локали, что обеспечивает немедленное обновление вашего приложения с учетом календаря пользователя и языковых настроек в Settings.app
person ChrisJF    schedule 21.12.2016

person    schedule
comment
Разве вам не нужно включать компонент эпохи? - person Chris Page; 23.10.2011
comment
Мне пришлось удалить NSDayCalendarUnit и добавить NSWeekdayCalendarUnit при вычислении DateLastWeek. - person jessecurry; 01.12.2011
comment
Apple изменила определение NSWeekdayCalendarUnit и NSDayCalendarUnit около iOS 5.0. Новый способ - использовать NSWeekdayCalendarUnit. Но в более старых версиях вы должны использовать NSDayCalendarUnit. Это бардак... - person Dustin; 05.06.2013
comment
@Dustin Кажется, что не работает, даже при обновлении до новых единиц ... Например, для DateThisWeek установка дня недели не влияет на NSDate ... - person AnthoPak; 20.03.2019

person    schedule
comment
Поскольку оба действительны для получения текущей даты, оба включают время. Так что это неправильное решение вопроса! - person Christian Beer; 14.11.2011