NSDate uzyskać rok / miesiąc / dzień

291

Jak mogę uzyskać rok / miesiąc / dzień NSDateobiektu, bez innych informacji? Zdaję sobie sprawę, że prawdopodobnie mógłbym to zrobić z czymś podobnym do tego:

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

Ale wydaje się, że jest to bardzo kłopotliwe dla czegoś tak prostego, jak uzyskanie NSDateroku / miesiąca / dnia. Czy jest jakieś inne rozwiązanie?

Richard J. Ross III
źródło
4
Miałem trochę problemów z użyciem tego kodu, dopóki nie zmieniłem pierwszego wiersza na „NSCalendar * cal = [[NSCalendar przydziel]] initWithCalendarIdentifier: NSGregorianCalendar];” Musiała nastąpić zmiana w interfejsie API, ponieważ zadano to pytanie.
Russell Thackston
@ futureelite7 przywrócono do wersji 1. Kod istnieje do celów historycznych i był prostym wyjaśnieniem mojego początkowego pomysłu.
Richard J. Ross III
Kod już nie działa. Czy potrafisz zanotować poprawny kod?
futureelite7,
@ futureelite7 no. Ten kod był pokazem mojej pierwszej próby, nigdy nie miał działać. Jeśli uważasz, że jest to niejednoznaczne, możesz edytować kontekst otaczający ten blok kodu, ale nie edytuj samego kodu. Jeśli uważasz, że edytujesz sam kod, bardzo mocno, zabierz to omówienie do meta, a my zobaczymy, co mają do powiedzenia inne mody.
Richard J. Ross III
8
@ Mike, dlatego czytasz odpowiedzi, a nie pytanie.
Richard J. Ross III

Odpowiedzi:

615

Ponieważ jest to najwyraźniej moja najpopularniejsza odpowiedź, spróbuję ją edytować, aby zawierała nieco więcej informacji.

Pomimo swojej nazwy, NSDatesama w sobie oznacza po prostu punkt w czasie maszyny, a nie datę. Nie ma korelacji między punktem w czasie określonym przez NSDatea rok, miesiąc lub dzień. W tym celu musisz odwołać się do kalendarza. Dowolny moment zwróci informacje o różnych datach w oparciu o kalendarz, na który patrzysz (daty nie są takie same, na przykład w kalendarzu gregoriańskim i żydowskim), a kalendarz gregoriański jest najczęściej używanym kalendarzem w świat - zakładam - jesteśmy trochę stronniczy, że NSDatezawsze powinniśmy go używać. NSDate, na szczęście jest o wiele bardziej dwustronny.


Jak NSCalendarwspomniałeś, uzyskanie daty i godziny będzie musiało upłynąć , ale jest na to prostszy sposób:

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

To generuje NSDateComponentsobiekt zawierający dzień, miesiąc i rok z bieżącego kalendarza systemowego dla bieżącego dnia. ( Uwaga: niekoniecznie jest to bieżący kalendarz określony przez użytkownika , tylko domyślny kalendarz systemowy).

Oczywiście, jeśli używasz innego kalendarza lub daty, możesz to łatwo zmienić. Lista dostępnych kalendarzy i jednostek kalendarza znajduje się w NSCalendarOdniesieniu do klasy . Więcej informacji na temat NSDateComponentsmożna znaleźć w NSDateComponentsOdwołaniu do klasy .


Dla porównania, dostęp do poszczególnych komponentów z NSDateComponentsjest raczej łatwy:

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

Musisz tylko uważać: NSDateComponentsnie będzie zawierał prawidłowych informacji dla pól, o które prosisz, chyba że wygenerowałeś je z tymi prawidłowymi informacjami (tj. Prośbą NSCalendaro przekazanie tych informacji NSCalendarUnit). NSDateComponentssame w sobie nie zawierają żadnych informacji referencyjnych - są to po prostu proste struktury, które przechowują liczby, do których masz dostęp. Jeśli chcesz również uzyskać erę, na przykład, z NSDateComponents, będziesz musiał karmić metodę z generatora NSCalendarz NSCalendarUnitEraflagą.

Itai Ferber
źródło
3
Korekta tego, pierwsza linia powinna mieć NSDayCalendarUnit zamiast NSWeekCalendarUnit.
whitehawk
@Erik Z którego kalendarza korzystasz? Kod?
Itai Ferber
7
@Jonny Otrzymane wyniki zależą od używanego kalendarza. NSCalendar„s +currentCalendarmetoda zwróci kalendarz systemowy, a więc jeśli telefon użytkownika jest ustawiona na tryb japoński lub tajski czasu, dostaniesz inny rok. Jeśli chcesz wymusić określony system kalendarza, utwórz kalendarz i zainicjuj go przy użyciu odpowiednich ustawień regionalnych. Na przykład, aby wymusić kalendarz gregoriański, należy użyć następujących opcji:[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]
Itai Ferber
2
wylicza NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit są DEPRECATED, zamiast tego użyj NSCalendarUnitDay.
Kunal Balani
2
Ostrzeżenie: nie używaj [NSCalendar currentCalendar], chyba że próbujesz pokazać wartość użytkownikowi. Weź pod uwagę, że użytkownicy mogą śledzić kalendarz buddyjski (rok to 2558 lub coś takiego) lub dowolną liczbę nieparzystych kalendarzy. W takich przypadkach nie chcesz, aby aplikacja się zepsuła. Użyj kalendarza gregoriańskiego, chyba że masz bardzo konkretny powód, aby tego nie robić. Ten błąd jest trudny do wykrycia, ponieważ ty i twoi testerzy możecie domyślnie używać gregoriańskiego.
n13
51

Możesz uzyskać oddzielny składnik NSDate za pomocą 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]];

Jeśli chcesz uzyskać numer miesiąca zamiast skrótu, użyj „MM”. Jeśli chcesz uzyskać liczby całkowite, użyj[myDayString intValue];

skocko76
źródło
1
Rozszerzył się na niego dzięki tej istocie . Baw się dobrze - możesz to upuścić w swoim kodzie.
DogEatDog
Rozwiązałem problem z używaniem dat do wyszukiwania w słowniku :) Dzięki!
mlunoe,
1
To faktycznie nie działa w 100% zgodnie z oczekiwaniami przez cały czas. Na przykład, jeśli data
NSDate to 2013-12-31
jak mogę uzyskać dzień roku, np. 10 kwietnia to dzień 99. dnia bieżącego roku? -
Programista iOS
17

Aby przeredagować doskonały (i działający!) Kod Itai, oto jak wyglądałaby przykładowa klasa pomocnicza, aby zwrócić wartość roku danej zmiennej NSDate.

Jak widać, wystarczy zmodyfikować ten kod, aby uzyskać miesiąc lub dzień.

+(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;
}

(Nie mogę uwierzyć, że musimy napisać własne podstawowe funkcje daty iOS w 2013 roku ...)

Jeszcze jedno: nigdy nie używaj <i> do porównywania dwóch wartości NSDate.

XCode chętnie zaakceptuje taki kod (bez żadnych błędów i ostrzeżeń), ale jego wyniki są loterią. Państwo musi użyć funkcji „Porównaj” aby porównać NSDates:

if ([date1 compare:date2] == NSOrderedDescending) {
    // date1 is greater than date2        
}
Mike Gledhill
źródło
4
Wyniki porównania wskaźników dalekie są od loterii - mają bardzo dobrze zdefiniowane wyniki, o ile używa się ich do tego, do czego są przeznaczone - porównywania wskaźników, a nie obiektów.
Richard J. Ross III
To może nie być loteria, ale DateTime w C # jest znacznie bardziej intuicyjny. W iOS operator mniej niż powinien naprawdę porównywać dwie NSDate ... czy ktoś naprawdę chciałby porównać wskaźniki dwóch zmiennych NSDate? Przynajmniej program XCode pokazuje Ostrzeżenie, aby zapytać, czy tak naprawdę użytkownik naprawdę ma na myśli.
Mike Gledhill
1
To tylko znak leniwego programisty, który nie rozumie podstaw języka, w którym pisze. I zdarzały się sytuacje, w których porównania wskaźników są konieczne dla obiektów ObjC - zwłaszcza jeśli tworzysz niestandardowy kontener (chociaż rzeczy stają się dziwniejsze z ARC).
Richard J. Ross III
1
Muszę być leniwym programistą, który nie rozumie podstaw, ale to świetna wskazówka Mike!
Pier-Luc Gendreau
4
Porównanie wskaźników może być konieczne, ale są one znacznie mniej powszechnym przypadkiem użycia przy porównywaniu dwóch dat. 99,99% czasu, gdy dowolny programista byłby bardziej zainteresowany porównywaniem dat niż wskazówkami. Zasadniczo C # i platforma .NET zostały zaprojektowane w celu ułatwienia najpopularniejszych scenariuszy, a tym samym zwiększenia produktywności programistów, aw wielu przypadkach cel-c sprawia, że ​​celowo staje się to bardziej uciążliwe. Jeśli masz czas, aby przeczytać 800-stronicową książkę na temat podstaw każdego języka, na zdrowie, ale reszta z nas ma aplikacje, które można dostarczyć na czas i przy założonym budżecie.
Crake
16

W 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)
NatashaTheRobot
źródło
11

Piszę tę odpowiedź, ponieważ jest to jedyne podejście, które nie zwraca opcji przed NSDateComponentzmiennymi i / lub wymusza ich rozpakowywanie (także w Swift 3).

Szybki 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)

Dodatkowa zabawna wersja 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)
Kevin
źródło
jak mogę uzyskać dzień roku, np. 10 kwietnia to dzień 99. dnia bieżącego roku? -
Programista iOS
I upewnij się, że używasz kalendarza gregoriańskiego, np. Składnik roku w kalendarzu japońskim zwraca 1 cyfrę.
Flovettee
8

Nowości w iOS 8

ObjC

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

Szybki

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)
Yuchen Zhong
źródło
2
Niesamowity! @Yuchen Zhong
Lito
1
Znakomity ! O wiele lepsza składnia!
joan
4

Jeśli celujesz w iOS 8+, możesz skorzystać z nowych NSCalendarmetod wygody, aby osiągnąć ten cel w bardziej zwięzłym formacie.

Najpierw utwórz NSCalendari użyj tego, co NSDatejest wymagane.

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

Możesz wyodrębnić komponenty indywidualnie poprzez component:fromDate:

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

Lub, bardziej zwięźle, użyj NSIntegerwskaźników za pośrednictwemgetEra:year:month:day:fromDate:

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

Aby uzyskać więcej informacji i przykładów, zapoznaj się z NSDate Manipulation Made Easy w iOS 8 . Uwaga, napisałem post.

Joe Masilotti
źródło
jak mogę uzyskać dzień roku, np. 10 kwietnia to dzień 99. dnia bieżącego roku? -
Programista iOS
4

Począwszy od systemu iOS 8.0 (i OS X 10), można użyć metody komponentu , aby uprościć uzyskanie komponentu z jedną datą:

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

Powinno to uprościć i mam nadzieję, że zostanie to skutecznie wdrożone.

Christopher King
źródło
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);
Linh Nguyen
źródło
To dość wyraźnie nie podaje mi roku, miesiąca ani dnia jako liczby całkowitej, o co prosiłem w OP. -1.
Richard J. Ross III
1
Richard J. Ross III: Właśnie to naprawiłem, przepraszam, ponieważ moja odpowiedź nie dotarła do twojego pytania.
Linh Nguyen
2

Oto rozwiązanie w 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) 
Nitin Nain
źródło
2

Spróbuj tego . . .

Fragment kodu:

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

Podaje bieżący rok, miesiąc, datę

Yogeesh HT
źródło
1

Spróbuj wykonać następujące czynności:

    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];
loretoparisi
źródło
1

Swift 2.x

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

Możesz użyć go jako

NSDate().currentDateInDayMonthYear()

Wynik

6 March 2016
Alserda
źródło
1

Szybki

Łatwiejszy sposób na uzyskanie dowolnych elementów daty jako opcjonalnego ciągu.

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")
Krunal
źródło
0

robię w ten sposób ....

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);
Shaik Riyaz
źródło
0

Aby uzyskać ciąg czytelny dla człowieka (dzień, miesiąc, rok), możesz:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *string = [dateFormatter stringFromDate:dateEndDate];
mirap
źródło