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, оскільки це питання було задано.
Рассел Такстон

@ futureelite7 повернувся до редакції 1. Код, який існує для історичних цілей, і був простим поясненням того, що було моєю початковою ідеєю.
Річард Дж. Росс III

Код більше не працює. Чи можете ви зробити примітку до правильного коду?
futureelite7

@ futureelite7 ні. Цей код був показом моєї першої спроби, він ніколи не мав на меті працювати. Якщо ви вважаєте, що це неоднозначно, не соромтесь редагувати контекст навколо цього кодового блоку, але не редагуйте сам код. Якщо ви дуже сильно ставитеся до редагування самого коду, то будь ласка, перейдіть до цього обкладинки на мета і ми побачимо, що мають сказати інші модники.
Річард Дж. Росс 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.
whitehawk

@Erik Який календар ви використовуєте? Код?
Ітаї Фербер

7
@Jonny Отримані результати залежать від використовуваного календаря. NSCalendar«S +currentCalendarметод повертає календар системи, і тому , якщо телефон користувача встановлений в режимі японської або тайське час, ви отримаєте інший рік. Якщо ви хочете примусити певну систему календарів, створіть календар та ініціалізуйте його з належною мовою. Наприклад, щоб змусити григоріанський календар, ви хочете скористатися наступним:[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]
Itai Ferber

2
перераховує NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit ВИМОЖЕНИЙ замість цього використовувати NSCalendarUnitDay.
Kunal Balani

2
Попередження: Не використовуйте [NSCalendar currentCalendar], якщо ви не намагаєтеся показати користувачеві значення. Подумайте, що користувачі можуть дотримуватися буддійського календаря (рік нарахування 2558 чи інший) або будь-яку іншу кількість непарних календарів. Ви не хочете, щоб ваш додаток не працював у цих випадках. Використовуйте григоріанський календар, якщо у вас немає зовсім конкретних причин цього не робити. Цю помилку важко наздогнати, оскільки ви та ваші тестери можуть використовуватись як григоріанський за замовчуванням.
n13,

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]];

Якщо ви хочете отримати номер місяця замість абревіатури, використовуйте "MM". Якщо ви хочете отримати цілі числа, використовуйте[myDayString intValue];


1
Розгорнув його за допомогою цієї суті . Розважайтеся --- ви можете вписати це у свій код.
DogEatDog

Вирішив мою проблему з використанням дат для пошуку у словнику :) Дякую!
mlunoe

1
Це насправді не працює на 100%, як очікували весь час. Наприклад, якщо NSDate - 2013-12-31 00:00:00 +0000, то відформатована дата поверне 2014 рік за рік, навіть якщо фактична кількість в даті - 2013.
margusholland

як я можу отримати день року, наприклад, 10 квітня поточний день - 99-й день поточного року ?? -
Розробник iOS

17

Просто для перетворення чудового (і працюючого!) Коду Itai, ось як виглядатиме зразок помічника, щоб повернути значення року даної змінної 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, менший, ніж оператор, дійсно повинен порівнювати два NSDates ... чи дійсно хтось хотів би порівняти покажчики двох змінних NSDate? Принаймні, шоу XCode демонструє попередження, щоб запитати, чи дійсно це означає, що користувач насправді означає.
Майк Гледхілл

1
Це лише знак ледачого кодера, який не розуміє основ мови, на якій він пише. І для мене були ситуації, коли порівняння вказівників необхідне для об’єктів ObjC, особливо якщо ви створюєте спеціальний контейнер (хоча речі стають більш дивними з ARC).
Річард Дж. Росс III

1
Я, мабуть, лінивий кодер, який не розуміє основ, але це чудова порада Майка!
П’єр-Люк Джендро

4
Порівняння покажчиків може бути необхідним, але вони є набагато рідшим випадком використання при порівнянні двох дат. 99,99% часу будь-якому програмісту було б більше цікаво порівняти дати, а не покажчики. По суті, C # та .NET Framework були розроблені для полегшення найбільш поширених сценаріїв, тим самим роблячи програмістів більш продуктивними, а в багатьох випадках об’єктивно-c вважає, що це робить речі навмисно більш важкими. Якщо у вас є час, щоб прочитати книгу на 800 сторінках про основи кожної мови, привіт, але решта з нас мають додатки для доставки вчасно та на бюджет.
Крейк

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)

Швидкий 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)

Bonus 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

І переконайтеся, що ви використовуєте григоріанський календар, наприклад, компонент року для японського календаря повертає 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
Lito

1
Блискуче! Шлях кращий синтаксис!
Джоан

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 , спрощеною в iOS 8 . Заперечення, я написав пост.


як я можу отримати день року, наприклад, 10 квітня поточний день - 99-й день поточного року ?? -
Розробник iOS

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

Швидкий 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.