NSDate obtém ano / mês / dia


291

Como posso obter o ano / mês / dia de um NSDateobjeto, sem outras informações? Percebo que provavelmente poderia fazer isso com algo semelhante a isto:

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

Mas isso parece ser muito complicado para algo tão simples quanto obter um NSDateano / mês / dia. existe alguma outra solução?


4
Ocorreu um problema ao usar esse código até alterar a primeira linha para "NSCalendar * cal = [[alocação de NSCalendar] initWithCalendarIdentifier: NSGregorianCalendar];" Deve ter havido uma alteração na API desde que essa pergunta foi feita.
22812 Russell Thackston

@ futureelite7 retornou à revisão 1. O código existe para fins históricos e foi uma explicação simples de qual era minha ideia inicial.
Richard J. Ross III

O código não funciona mais. Você pode anotar o código correto?
futureelite7

@ futureelite7 no. Esse código foi uma demonstração da minha primeira tentativa, nunca teve a intenção de funcionar. Se você acha que isso é ambíguo, fique à vontade para editar o contexto em torno desse bloco de código, mas não edite o próprio código. Se você se sente extremamente fortemente em editar o próprio código, leve esta cobertura para meta e veremos o que outros mods têm a dizer.
Richard J. Ross III

8
@ Mike é por isso que você lê as respostas, não a pergunta.
Richard J. Ross III

Respostas:


615

Como essa é aparentemente a minha resposta mais popular, tentarei editá-la para conter um pouco mais de informação.

Apesar do nome, NSDatepor si só marca um ponto no tempo da máquina, não uma data. Não há correlação entre o ponto no tempo especificado por NSDatee um ano, mês ou dia. Para isso, você deve consultar um calendário. Qualquer ponto no tempo retornará informações de data diferentes com base no calendário que você está visualizando (as datas não são as mesmas nos calendários gregoriano e judaico, por exemplo) e, embora o calendário gregoriano seja o calendário mais usado no mundo - presumo - somos um pouco tendenciosos que NSDatesempre devem usá-lo. NSDate, felizmente, é muito mais bipartidário.


A obtenção de data e hora terá que passar NSCalendar, como você mencionou, mas há uma maneira mais simples de fazer isso:

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

Isso gera um NSDateComponentsobjeto que contém o dia, mês e ano do calendário atual do sistema para o dia atual. ( Nota: este não é necessariamente o calendário atual especificado pelo usuário , apenas o calendário padrão do sistema.)

Obviamente, se você estiver usando um calendário ou data diferente, poderá mudar isso facilmente. Uma lista de calendários e unidades de calendário disponíveis pode ser encontrada na NSCalendarReferência da turma . Mais informações NSDateComponentspodem ser encontradas na NSDateComponentsReferência de classe .


Para referência, o acesso a componentes individuais a partir do NSDateComponentsé bastante fácil:

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

Você só precisa ter cuidado: NSDateComponentsnão conterá informações válidas para os campos solicitados, a menos que você os tenha gerado com essas informações válidas (por exemplo, solicitação NSCalendarpara fornecer essas informações NSCalendarUnit) NSDateComponentsnão contêm informações de referência por si só - são apenas estruturas simples que contêm números para você acessar. Se você também deseja obter uma era, por exemplo, NSDateComponentsprecisará alimentar o método gerador NSCalendarcom a NSCalendarUnitErabandeira.


3
Uma correção para isso, a primeira linha deve ter NSDayCalendarUnit em vez de NSWeekCalendarUnit.
Whitehawk

@Erik Qual calendário você está usando? Código?
Itai Ferber

7
@ Jonny Os resultados obtidos dependem do calendário que você está usando. NSCalendarO +currentCalendarmétodo retornará o calendário do sistema e, se o telefone do usuário estiver definido no modo de horário japonês ou tailandês, você terá um ano diferente. Se você deseja forçar um sistema de calendário específico, crie um calendário e inicialize-o com o código do idioma apropriado. Por exemplo, para forçar um calendário gregoriano, você vai querer usar o seguinte:[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]
Itai Ferber

2
enumerações NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit DEPRECATED, use NSCalendarUnitDay.
Kunal Balani

2
Aviso: não use [NSCalendar currentCalendar], a menos que esteja tentando mostrar um valor ao usuário. Considere que os usuários podem seguir um calendário budista (o ano agora é 2558 ou algo assim) ou qualquer outro número de calendários ímpares. Você não deseja que seu aplicativo seja interrompido nesses casos. Use o calendário gregoriano, a menos que você tenha um motivo muito específico para não fazê-lo. Esse bug é difícil de detectar, pois você e seus testadores podem usar o gregoriano como padrão.
n13

51

Você pode obter um componente separado de um NSDate usando o 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]];

Se você deseja obter o número do mês em vez da abreviação, use "MM". Se você deseja obter números inteiros, use[myDayString intValue];


1
Expandido sobre ele com essa essência . Divirta-se --- você pode colocar isso no seu código.
dogeatdog

Resolvi meu problema ao usar datas para pesquisar em um dicionário :) Obrigado!
mlunoe

1
Na verdade, isso não funciona 100% como esperado o tempo todo. Por exemplo, se o NSDate for 2013-12-31 00:00:00 +0000, a data formatada retornará 2014 para o ano, mesmo que o número real na data seja 2013.
margusholland

como posso obter o dia do ano, por exemplo, 10 de abril é o dia atual é o 99º dia do ano atual? -
iOS desenvolvedor

17

Apenas para reformular o código excelente (e funcionando!) Do Itai, eis a aparência de uma classe auxiliar de amostra, para retornar o valor do ano de uma determinada variável NSDate.

Como você pode ver, é fácil modificar esse código para obter o mês ou o dia.

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

(Não acredito que precisamos escrever nossas próprias funções básicas de data para iOS, em 2013 ...)

Outra coisa: nunca use <e> para comparar dois valores do NSDate.

O XCode aceitará com prazer esse código (sem erros ou avisos), mas seus resultados são uma loteria. Você deve usar a função "compare" para comparar o NSDates:

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

4
Os resultados da comparação de ponteiros estão longe de ser uma loteria - eles têm resultados muito bem definidos, desde que você os utilize para o que eles se destinam - comparando ponteiros, não objetos.
Richard J. Ross III

Pode não ser uma loteria, mas o DateTime do C # é muito mais intuitivo. No iOS, o operador menor que realmente deve comparar dois NSDates ... alguém realmente gostaria de comparar os ponteiros de duas variáveis ​​do NSDate? No mínimo, o XCode show mostra um Aviso para perguntar se é realmente isso que o usuário realmente quer dizer.
Mike Gledhill

1
Isso é apenas um sinal de um codificador preguiçoso que não entende os fundamentos da linguagem em que está escrevendo. E, houve situações em que as comparações de ponteiros são necessárias para objetos ObjC - especialmente se você estiver criando um contêiner personalizado (embora as coisas ficam mais estranhas com o ARC).
Richard J. Ross III

1
Eu devo ser um programador preguiçoso que não entende os fundamentos, mas essa é uma ótima dica, Mike!
Pier-Luc Gendreau 22/10

4
As comparações de ponteiro podem ser necessárias, mas são o caso de uso muito menos comum ao comparar duas datas. 99,99% do tempo, qualquer programador estaria mais interessado em comparar as datas do que os indicadores. Fundamentalmente, o C # e a estrutura .NET foram projetados para facilitar os cenários mais comuns, tornando os programadores mais produtivos e, em muitos casos, o objetivo-c parece tornar as coisas intencionalmente mais árduas. Se você tiver tempo para ler um livro de 800 páginas sobre os fundamentos de todos os idiomas, parabéns, mas o resto de nós tem aplicativos para entregar dentro do prazo e do orçamento.
Crake

16

No 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

Estou escrevendo esta resposta porque é a única abordagem que não fornece opcionais a partir de NSDateComponentvariáveis ​​e / ou força a desembrulhar essas variáveis ​​(também para o Swift 3).

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

Bonus Swift 3 versão divertida

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)

como posso obter o dia do ano, por exemplo, 10 de abril é o dia atual é o 99º dia do ano atual? -
iOS desenvolvedor

E certifique-se de usar o calendário gregoriano, por exemplo, o componente do ano para o calendário japonês retorna 1 dígito ..
Flovettee 17/04

8

Novo no iOS 8

ObjC

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

Rápido

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
Surpreendente! @Yuchen Zhong
Lito

1
Brilhante! Muito melhor sintaxe!
Joan

4

Se você estiver segmentando o iOS 8 ou superior, poderá usar os novos NSCalendarmétodos de conveniência para conseguir isso em um formato mais conciso.

Primeiro crie um NSCalendare use o que NSDatefor necessário.

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

Você pode extrair componentes individualmente via component:fromDate:

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

Ou, ainda mais sucintamente, use NSIntegerponteiros viagetEra:year:month:day:fromDate:

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

Para obter mais informações e exemplos, consulte o NSDate Manipulation Made Easy no iOS 8 . Disclaimer, eu escrevi o post.


como posso obter o dia do ano, por exemplo, 10 de abril é o dia atual é o 99º dia do ano atual? -
iOS desenvolvedor

4

No iOS 8.0 (e no OS X 10), você pode usar o método component para simplificar a obtenção de um único componente de data, como:

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

Deve tornar as coisas mais simples e espero que isso seja implementado com eficiência.



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

Isso claramente não me dá o ano, mês ou dia como um número inteiro, o que solicitei no OP. -1.
Richard J. Ross III

1
Richard J. Ross III: Acabei de corrigir, desculpe-me porque minha resposta foi perdida.
Linh Nguyen

2

Aqui está a solução no 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

Tente isso. . .

Fragmento de código:

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

Dá ano, mês, data atual


1

Tente o seguinte:

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

Você pode usá-lo como

NSDate().currentDateInDayMonthYear()

Resultado

6 March 2016

1

Rápido

A maneira mais fácil de obter qualquer elemento de data como uma String opcional.

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

eu faço assim ....

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

Para obter uma sequência legível por humanos (dia, mês, ano), você pode:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *string = [dateFormatter stringFromDate:dateEndDate];
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.