NSDate получить год / месяц / день


291

Как я могу получить год / месяц / день NSDateобъекта, если нет другой информации? Я понимаю, что я мог бы сделать это с чем-то похожим на это:

NSCalendar *cal = [[NSCalendar alloc] init];
NSDateComponents *components = [cal components:0 fromDate:date];
int year = [components year];
int month = [components month];
int day = [components day];

Но это, кажется, много хлопот для чего-то такого простого, как получение NSDateгода / месяца / дня. Есть ли другое решение?


4
У меня были небольшие проблемы с использованием этого кода, пока я не изменил первую строку на «NSCalendar * cal = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];» Должно быть, было изменение в API, так как этот вопрос был задан.
Рассел Тэкстон,

@utureelite7 откатился до ревизии 1. Код существует для исторических целей и был простым объяснением моей первоначальной идеи.
Ричард Дж. Росс III

Код больше не работает. Можете ли вы записать правильный код?
futureelite7

@ futureelite7 нет. Этот код был демонстрацией моей первой попытки, он никогда не был предназначен для работы. Если вы чувствуете, что это неоднозначно, не стесняйтесь редактировать контекст, окружающий этот блок кода, но не редактируйте сам код. Если вы крайне настойчиво относитесь к редактированию самого кода, тогда, пожалуйста, перенесите это покрытие в meta, и мы посмотрим, что скажут другие моды.
Ричард Дж. Росс III

8
@mike, вот почему вы читаете ответы, а не вопрос.
Ричард Дж. Росс III

Ответы:


615

Поскольку это, по-видимому, мой самый популярный ответ, я постараюсь отредактировать его, чтобы он содержал немного больше информации.

Несмотря на свое название, NSDateсамо по себе это просто точка машинного времени, а не дата. Не существует корреляции между моментом времени, указанным NSDateи годом, месяцем или днем. Для этого вам нужно обратиться к календарю. Любой данный момент времени будет возвращать различную информацию о дате в зависимости от того, какой календарь вы просматриваете (например, даты не совпадают в григорианском и еврейском календарях), а григорианский календарь является наиболее широко используемым календарем в Мир - я предполагаю - мы немного предвзяты, что NSDateвсегда должны его использовать. NSDateК счастью, гораздо более двухпартийный.


Как NSCalendarвы упомянули, получение даты и времени должно будет пройти , но есть более простой способ сделать это:

NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]];

Это создает NSDateComponentsобъект, содержащий день, месяц и год из текущего системного календаря на текущий день. ( Примечание: это не обязательно текущий пользовательский календарь, а только системный календарь по умолчанию.)

Конечно, если вы используете другой календарь или дату, вы можете легко это изменить. Список доступных календарей и календарных единиц можно найти в NSCalendarсправочнике классов . Более подробную информацию о NSDateComponentsможно найти в NSDateComponentsсправочнике классов .


Для справки, получить доступ к отдельным компонентам из NSDateComponentsдовольно просто:

NSInteger day = [components day];
NSInteger month = [components month];
NSInteger year = [components year];

Вы просто должны быть внимательны: NSDateComponentsне будет содержать достоверную информацию для каких-либо полей, которые вы запрашиваете, если только вы не сгенерировали их с этой действительной информацией (т.е. запросите NSCalendarпредоставление этой информации с помощью NSCalendarUnits). NSDateComponentsсами по себе не содержат справочной информации - это просто простые структуры, которые содержат номера для доступа к ним. Если вы хотите также получить эру, например, NSDateComponentsвам нужно передать метод генератора из NSCalendarс NSCalendarUnitEraфлагом.


3
Исправление к этому, первая строка должна иметь NSDayCalendarUnit вместо NSWeekCalendarUnit.
Уайтхок

@Erik Какой календарь вы используете? Код?
Итай Фербер

7
@Jonny Результаты, которые вы получаете, зависят от календаря, который вы используете. NSCalendar«s +currentCalendarметод возвращает календарь системы, и поэтому , если телефон пользователя установлен в режиме японской или тайское время, вы получите другой год. Если вы хотите форсировать определенную календарную систему, создайте календарь и инициализируйте его с правильным языком. Например, для форсирования григорианского календаря вам понадобится следующее:[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]
Итай Фербер

2
перечисления NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit УСТАРЕЛО, вместо этого используйте NSCalendarUnitDay.
Кунал Балани

2
Предупреждение: не используйте [NSCalendar currentCalendar], если вы не пытаетесь показать значение пользователю. Учтите, что пользователи могут следовать буддийскому календарю (сейчас 2558 или около того) или любому другому количеству нечетных календарей. Вы не хотите, чтобы ваше приложение сломалось в этих случаях. Используйте григорианский календарь, если у вас нет особых причин не делать этого. Эту ошибку трудно уловить, потому что вы и ваши тестеры по умолчанию можете использовать григорианский.
13

51

Вы можете получить отдельный компонент NSDate, используя NSDateFormatter:

NSDateFormatter *df = [[NSDateFormatter alloc] init];

[df setDateFormat:@"dd"];
myDayString = [df stringFromDate:[NSDate date]];

[df setDateFormat:@"MMM"];
myMonthString = [df stringFromDate:[NSDate date]];

[df setDateFormat:@"yy"];
myYearString = [df stringFromDate:[NSDate date]];

Если вы хотите получить номер месяца вместо сокращения, используйте «ММ». Если вы хотите получить целые числа, используйте[myDayString intValue];


1
Рассказал его с этой сущностью . Веселитесь - вы можете добавить это в свой код.
DogEatDog

Решил мою проблему с использованием дат для поиска в словаре :) Спасибо!
млунное

1
Это на самом деле не работает на 100%, как ожидалось все время. Например, если NSDate равен 2013-12-31 00:00:00 +0000, то форматированная дата вернет 2014 год за год, даже если фактическое число в дате - 2013.
margusholland

как я могу получить день года, например, 10 апреля - это текущий день - 99-й день текущего года? -
iOS Developer

17

Просто перефразировать с превосходными Итай (и работает) код, вот что образец вспомогательный класс будет выглядеть, чтобы вернуться в год значение данной переменной NSDate.

Как видите, этот код достаточно легко изменить, чтобы получить месяц или день.

+(int)getYear:(NSDate*)date
{
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:date];

    int year = [components year];
    int month = [components month];
    int day = [components day];

    return year;
}

(Я не могу поверить, что мы должны написать наши собственные основные функции даты iOS, как это, в 2013 году ...)

Еще одна вещь: никогда не используйте <и> для сравнения двух значений NSDate.

XCode с радостью примет такой код (без каких-либо ошибок или предупреждений), но его результаты - лотерея. Вы должны использовать функцию сравнения для сравнения NSDates:

if ([date1 compare:date2] == NSOrderedDescending) {
    // date1 is greater than date2        
}

4
Результаты сравнения указателей далеки от лотереи - они имеют очень четко определенные результаты, если вы используете их для того, для чего они предназначены - сравнения указателей, а не объектов.
Ричард Дж. Росс III

Это может быть не лотерея, но DateTime в C # гораздо более интуитивно понятен. В iOS оператор «меньше» действительно должен сравнивать две NSDate ... кто-нибудь действительно хотел бы сравнить указатели двух переменных NSDate? По крайней мере, шоу XCode показывает предупреждение, чтобы спросить, действительно ли это означает пользователь.
Майк Глэдхилл

1
Это просто признак ленивого кодера, который не понимает основ языка, на котором он пишет. И для меня были ситуации, когда для объектов ObjC необходимо сравнение указателей - особенно если вы создаете пользовательский контейнер (хотя с ARC дела обстоят страннее).
Ричард Дж. Росс III

1
Я должен быть ленивым программистом, который не понимает основ, но это отличный совет, Майк!
Пьер-Люк Жандро

4
Сравнения указателей могут быть необходимы, но они гораздо реже используются при сравнении двух дат. В 99,99% случаев любой программист будет более заинтересован в сравнении дат, а не указателей. Фундаментально C # и .NET Framework были разработаны для упрощения наиболее распространенных сценариев, что делает программистов более продуктивными, а во многих случаях объективным c кажется, что это делает дела преднамеренно более трудными. Если у вас есть время, чтобы прочитать книгу на 800 страниц, посвященную основам каждого языка, ура, но у остальных из нас есть приложения, которые можно доставить вовремя и в рамках бюджета.
Crake

16

В Swift 2.0:

    let date = NSDate()
    let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!
    let components = calendar.components([.Month, .Day], fromDate: date)

    let (month, day) = (components.month, components.day)

11

Я пишу этот ответ, потому что это единственный подход, который не возвращает вам необязательные NSDateComponentпеременные и / или не заставляет их разворачивать (также для Swift 3).

Свифт 3

let date = Date()
let cal = Calendar.current
let year = cal.component(.year, from: date)
let month = cal.component(.month, from: date)
let day = cal.component(.day, from: date)

Swift 2

let date = NSDate()
let cal = NSCalendar.currentCalendar()
let year = cal.component(.Year, fromDate: date)
let month = cal.component(.Month, fromDate: date)
let day = cal.component(.Day, fromDate: date)

Бонус Swift 3 веселая версия

let date = Date()
let component = { (unit) in return Calendar.current().component(unit, from: date) }
let year = component(.year)
let month = component(.month)
let day = component(.day)

как я могу получить день года, например, 10 апреля - это текущий день - 99-й день текущего года? -
iOS Developer

И убедитесь, что вы используете григорианский календарь, например, компонент года для японского календаря возвращает 1 цифру.
Flovettee

8

Новое в iOS 8

ObjC

NSDate *date = [NSDate date];
NSInteger era, year, month, day;
[[NSCalendar currentCalendar] getEra:&era year:&year month:&month day:&day fromDate:date];

стриж

let date = NSDate.init()
var era = 0, year = 0, month = 0, day = 0
NSCalendar.currentCalendar().getEra(&era, year:&year, month:&month, day:&day, fromDate: date)

2
Удивительный! @Yuchen Zhong
Лито

1
Блестящий! Намного лучше синтаксис!
Joan

4

Если вы ориентируетесь на iOS 8+, вы можете использовать новые NSCalendarудобные методы для достижения этого в более кратком формате.

Сначала создайте NSCalendarи используйте все, что NSDateтребуется.

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [NSDate date];

Вы можете извлечь компоненты по отдельности через component:fromDate:

NSInteger year = [calendar component:NSCalendarUnitYear fromDate:date];
NSInteger month = [calendar component:NSCalendarUnitMonth fromDate:date];
NSInteger day = [calendar component:NSCalendarUnitDay fromDate:date];

Или, еще более кратко, используйте NSIntegerуказатели черезgetEra:year:month:day:fromDate:

NSInteger year, month, day;
[calendar getEra:nil year:&year month:&month day:&day fromDate:date];

Для получения дополнительной информации и примеров посмотрите NSDate Manipulation Made Easy в iOS 8 . Отказ от ответственности, я написал пост.


как я могу получить день года, например, 10 апреля - это текущий день - 99-й день текущего года? -
iOS Developer

4

Начиная с iOS 8.0 (и OS X 10) вы можете использовать метод компонента, чтобы упростить получение одного компонента даты, например:

int year = [[NSCalendar currentCalendar] component:NSCalendarUnitYear fromDate:[NSDate date]];

Должно сделать вещи проще и, надеюсь, это будет реализовано эффективно.



2
    NSDate *currDate = [NSDate date];
    NSCalendar*       calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents* components = [calendar components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:currDate];
    NSInteger         day = [components day];
    NSInteger         month = [components month];
    NSInteger         year = [components year];
    NSLog(@"%d/%d/%d", day, month, year);

Это совершенно ясно, что я не могу указать год, месяц или день как целое число, как я и просил в ОП. -1.
Ричард Дж. Росс III

1
Ричард Дж. Росс III: Я только что исправил это, извините, потому что мой ответ был потерян на ваш вопрос.
Линь Нгуен

2

Вот решение в Swift:

let todayDate = NSDate()
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!

// Use a mask to extract the required components. Extract only the required components, since it'll be expensive to compute all available values.
let components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: todayDate)

var (year, month, date) = (components.year, components.month, components.day) 

2

Попробуй это . , ,

Фрагмент кода:

 NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]];
 int year = [components year];
 int month = [components month];
 int day = [components day];

Это дает текущий год, месяц, дату


1

Попробуйте следующее:

    NSString *birthday = @"06/15/1977";
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"MM/dd/yyyy"];
    NSDate *date = [formatter dateFromString:birthday];
    if(date!=nil) {
        NSInteger age = [date timeIntervalSinceNow]/31556926;
        NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:date];
        NSInteger day = [components day];
        NSInteger month = [components month];
        NSInteger year = [components year];

        NSLog(@"Day:%d Month:%d Year:%d Age:%d",day,month,year,age);
    }
    [formatter release];

1

Swift 2.x

extension NSDate {
    func currentDateInDayMonthYear() -> String {
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "d LLLL yyyy"
        return dateFormatter.stringFromDate(self)
    }
}

Вы можете использовать его как

NSDate().currentDateInDayMonthYear()

Вывод

6 March 2016

1

стриж

Более простой способ получить любые элементы даты в виде необязательной строки.

extension Date {

  // Year 
  var currentYear: String? {
    return getDateComponent(dateFormat: "yy")
    //return getDateComponent(dateFormat: "yyyy")
  }

  // Month 
  var currentMonth: String? {
    return getDateComponent(dateFormat: "M")
    //return getDateComponent(dateFormat: "MM")
    //return getDateComponent(dateFormat: "MMM")
    //return getDateComponent(dateFormat: "MMMM")
  }


  // Day
  var currentDay: String? {
    return getDateComponent(dateFormat: "dd")
    //return getDateComponent(dateFormat: "d")
  }


  func getDateComponent(dateFormat: String) -> String? {
    let format = DateFormatter()
    format.dateFormat = dateFormat
    return format.string(from: self)
  }


}

let today = Date()
print("Current Year - \(today.currentYear)")  // result Current Year - Optional("2017")
print("Current Month - \(today.currentMonth)")  // result Current Month - Optional("7")
print("Current Day - \(today.currentDay)")  // result Current Day - Optional("10")

0

я так делаю ....

NSDate * mydate = [NSDate date];

NSCalendar * mycalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSCalendarUnit units = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;

NSDateComponents * myComponents  = [mycalendar components:units fromDate:mydate];

NSLog(@"%d-%d-%d",myComponents.day,myComponents.month,myComponents.year);

0

Чтобы получить удобочитаемую строку (день, месяц, год), вы можете сделать:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *string = [dateFormatter stringFromDate:dateEndDate];
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.