NSDate nhận năm / tháng / ngày


291

Làm thế nào tôi có thể nhận được năm / tháng / ngày của một NSDateđối tượng, không có thông tin nào khác? Tôi nhận ra rằng tôi có thể có thể làm điều này với một cái gì đó tương tự như thế này:

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

Nhưng điều đó dường như là rất nhiều rắc rối cho một cái gì đó đơn giản như nhận được một NSDatenăm / tháng / ngày. Còn có những giải pháp nào nữa ko?


4
Tôi đã gặp một chút rắc rối khi sử dụng mã này cho đến khi tôi thay đổi dòng đầu tiên thành "NSCalWiki * cal = [[NSCalWiki alloc] initWithCalWikiIdentifier: NSGregorianCalWiki];" Phải có một sự thay đổi đối với API vì câu hỏi này đã được hỏi.
Russell Thackston

@ Futureelite7 quay trở lại sửa đổi 1. Mã này dành cho mục đích lịch sử và là một lời giải thích đơn giản về ý tưởng ban đầu của tôi là gì.
Richard J. Ross III

Mã không còn hoạt động. Bạn có thể làm một ghi chú cho mã chính xác?
Futelite7

@ tương lai7 không. Mã đó là một hiển thị của nỗ lực đầu tiên của tôi, nó không bao giờ có ý định làm việc. Nếu bạn cảm thấy điều đó không rõ ràng, hãy thoải mái chỉnh sửa bối cảnh xung quanh khối mã đó, nhưng đừng tự chỉnh sửa mã. Nếu bạn cảm thấy cực kỳ mạnh mẽ về việc tự chỉnh sửa mã, thì vui lòng đưa phần bảo vệ này vào meta và chúng tôi sẽ xem các mod khác nói gì.
Richard J. Ross III

8
@mike đó là lý do tại sao bạn đọc câu trả lời, không phải câu hỏi.
Richard J. Ross III

Câu trả lời:


615

Bởi vì đây rõ ràng là câu trả lời phổ biến nhất của tôi, tôi sẽ cố gắng chỉnh sửa nó để chứa thêm một chút thông tin.

Mặc dù tên NSDatecủa nó, chỉ đơn giản là đánh dấu một điểm trong thời gian máy, không phải là một ngày. Không có mối tương quan giữa thời điểm được chỉ định bởi NSDatemột năm, tháng hoặc ngày. Đối với điều đó, bạn phải tham khảo một lịch. Bất kỳ thời điểm nào cũng sẽ trả về thông tin ngày khác nhau dựa trên lịch bạn đang xem (ví dụ: ngày không giống nhau trong cả lịch Gregorian và Do Thái), và trong khi lịch Gregorian là lịch được sử dụng rộng rãi nhất trong thế giới - tôi giả sử - chúng ta hơi thiên vị NSDatenên luôn luôn sử dụng nó. NSDate, may mắn, là nhiều lưỡng đảng hơn.


Nhận được ngày và thời gian sẽ phải đi qua NSCalendar, như bạn đã đề cập, nhưng có một cách đơn giản hơn để làm điều đó:

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

Điều đó tạo ra một NSDateComponentsđối tượng chứa ngày, tháng và năm từ lịch hệ thống hiện tại cho ngày hiện tại. ( Lưu ý: đây không nhất thiết là lịch do người dùng chỉ định hiện tại , chỉ là lịch mặc định của hệ thống.)

Tất nhiên, nếu bạn đang sử dụng một lịch hoặc ngày khác, bạn có thể dễ dàng thay đổi điều đó. Một danh sách các lịch và đơn vị lịch có sẵn có thể được tìm thấy trong NSCalendarTài liệu tham khảo lớp . Thông tin thêm về NSDateComponentscó thể được tìm thấy trong NSDateComponentsTài liệu tham khảo lớp .


Để tham khảo, truy cập các thành phần riêng lẻ từ NSDateComponentskhá dễ dàng:

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

Bạn chỉ cần lưu ý: NSDateComponentssẽ không chứa thông tin hợp lệ cho bất kỳ trường nào bạn yêu cầu trừ khi bạn tạo chúng với thông tin hợp lệ đó (nghĩa là yêu cầu NSCalendarcung cấp thông tin đó với NSCalendarUnits). NSDateComponentskhông chứa thông tin tham khảo trong chính chúng - chúng chỉ là các cấu trúc đơn giản chứa số để bạn truy cập. Nếu bạn cũng muốn để có được một kỷ nguyên, ví dụ, trong NSDateComponents, bạn sẽ phải nuôi các phương pháp phát từ NSCalendarvới NSCalendarUnitEracờ.


3
Để điều chỉnh vấn đề này, dòng đầu tiên nên có NSDayCalWikiUnit thay vì NSWeekCalWikiUnit.
Whitehawk

@Erik Bạn đang sử dụng lịch nào? Mã?
Itai Ferber

7
@Jonny Kết quả bạn nhận được tùy thuộc vào lịch bạn đang sử dụng. NSCalendar's +currentCalendarphương pháp sẽ trở lại với lịch hệ thống, và vì vậy nếu điện thoại của người dùng được thiết lập để chế độ thời gian Nhật Bản hoặc Thái Lan, bạn sẽ nhận được một năm khác nhau. Nếu bạn muốn buộc một hệ thống lịch cụ thể, hãy tạo một lịch và khởi tạo nó với ngôn ngữ thích hợp. Chẳng hạn, để buộc lịch Gregorian, bạn sẽ muốn sử dụng như sau:[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]
Itai Ferber

2
enum NSDayCalWikiUnit | NSMonthCalWikiUnit | Thay vào đó, NSYearCalWikiUnit được ĐỔI sử dụng NSCalWikiUnitDay.
Kunal Balani

2
Cảnh báo: Không sử dụng [NSCalWiki currentCalWiki] trừ khi bạn đang cố gắng hiển thị giá trị cho người dùng. Hãy xem xét rằng người dùng có thể theo lịch Phật giáo (năm nay là 2558 hoặc một cái gì đó) hoặc bất kỳ số lịch lẻ nào khác. Bạn không muốn ứng dụng của mình bị hỏng trong những trường hợp này. Sử dụng lịch gregorian trừ khi bạn có một lý do rất cụ thể không. Lỗi này rất khó bắt vì bạn và những người thử nghiệm của bạn đều có thể sử dụng gregorian làm mặc định.
n13

51

Bạn có thể nhận được thành phần riêng biệt của một NSDate bằng 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]];

Nếu bạn muốn lấy số tháng thay vì viết tắt, hãy sử dụng "MM". Nếu bạn muốn lấy số nguyên, hãy sử dụng[myDayString intValue];


1
Mở rộng khi anh ấy với ý chính này . Hãy vui vẻ --- bạn có thể thả mã này vào mã của bạn.
DogEatDog

Đã giải quyết vấn đề của tôi khi sử dụng ngày để tra cứu trong từ điển :) Cảm ơn!
mlunoe

1
Điều này thực sự không hoạt động 100% như mong đợi mọi lúc. Ví dụ: nếu NSDate là 2013-12-31 00:00:00 +0000 thì ngày được định dạng sẽ trở lại 2014 cho năm, ngay cả khi số thực tế trong ngày là 2013.
margusholland

Làm thế nào tôi có thể có được ngày trong năm, ví dụ: 10 tháng 4 là ngày hiện tại là ngày thứ 99 của năm hiện tại ?? -
Nhà phát triển iOS

17

Chỉ cần điều chỉnh lại mã xuất sắc (và đang hoạt động!) Của Itai, đây là giao diện của lớp trình trợ giúp mẫu, để trả về giá trị năm của một biến NSDate đã cho.

Như bạn có thể thấy, thật dễ dàng để sửa đổi mã này để có được tháng hoặc ngày.

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

(Tôi không thể tin rằng chúng ta phải viết các chức năng ngày cơ bản cho iOS của mình như thế này vào năm 2013 ...)

Một điều khác: đừng bao giờ sử dụng <và> để so sánh hai giá trị NSDate.

XCode sẽ vui vẻ chấp nhận mã đó (không có bất kỳ lỗi hoặc cảnh báo nào), nhưng kết quả của nó là xổ số. Bạn phải sử dụng chức năng "so sánh" để so sánh NSDates:

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

4
Kết quả so sánh con trỏ khác xa với xổ số - chúng có kết quả được xác định rất rõ, miễn là bạn sử dụng chúng cho mục đích của chúng - so sánh con trỏ, không phải đối tượng.
Richard J. Ross III

Nó có thể không phải là xổ số, nhưng DateTime của C # trực quan hơn nhiều. Trong iOS, toán tử ít hơn thực sự nên so sánh hai NSDate ... có ai thực sự muốn so sánh các con trỏ của hai biến NSDate không? Ít nhất, chương trình XCode hiển thị Cảnh báo để hỏi liệu đây có thực sự là ý nghĩa của người dùng hay không.
Mike Gledhill

1
Đó chỉ là dấu hiệu của một lập trình viên lười biếng, người không hiểu các nguyên tắc cơ bản của ngôn ngữ mà anh ta đang viết. Và, đã có những tình huống đối với tôi khi việc so sánh con trỏ là cần thiết cho các đối tượng ObjC - đặc biệt là nếu bạn đang tạo một thùng chứa tùy chỉnh (mặc dù mọi thứ trở nên kỳ lạ hơn với ARC).
Richard J. Ross III

1
Tôi phải là một lập trình viên lười biếng, người không hiểu các nguyên tắc cơ bản, nhưng đó là một mẹo tuyệt vời Mike!
Cầu tàu-Luc Gendreau

4
So sánh con trỏ có thể là cần thiết nhưng chúng là trường hợp sử dụng ít phổ biến hơn nhiều khi so sánh hai ngày. 99,99% thời gian mà bất kỳ lập trình viên nào cũng sẽ quan tâm hơn khi so sánh ngày tháng hơn là con trỏ. Về cơ bản C # và .NET framework được thiết kế để làm cho các kịch bản phổ biến nhất trở nên dễ dàng hơn, do đó làm cho các lập trình viên làm việc hiệu quả hơn và trong nhiều trường hợp khách quan-c cảm thấy như nó làm cho mọi thứ trở nên khó khăn hơn. Nếu bạn có thời gian để đọc một cuốn sách 800 trang về các nguyên tắc cơ bản của mọi ngôn ngữ, hãy cổ vũ, nhưng phần còn lại của chúng tôi có các ứng dụng để cung cấp đúng thời gian và ngân sách.
Crake

16

Trong 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

Tôi đang viết câu trả lời này bởi vì đó là cách tiếp cận duy nhất không cung cấp cho bạn các tùy chọn quay lại từ NSDateComponentcác biến và / hoặc buộc hủy bỏ các biến đó (cũng cho 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)

Phần thưởng Swift 3 phiên bản vui nhộn

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)

Làm thế nào tôi có thể có được ngày trong năm, ví dụ: 10 tháng 4 là ngày hiện tại là ngày thứ 99 của năm hiện tại ?? -
Nhà phát triển iOS

Và hãy chắc chắn rằng bạn sử dụng lịch Gregorian, ví dụ thành phần năm cho lịch Nhật Bản trả về 1 chữ số ..
Flovettee

8

Mới trong iOS 8

ObjC

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

Nhanh

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
Kinh ngạc! @Yuchen Zhong
Lito

1
Xuất sắc ! Cách tốt hơn cú pháp!
joan

4

Nếu bạn đang nhắm mục tiêu iOS 8+, bạn có thể sử dụng các NSCalendarphương pháp tiện lợi mới để đạt được điều này ở định dạng ngắn gọn hơn.

Đầu tiên tạo một NSCalendarvà sử dụng bất cứ điều gì NSDateđược yêu cầu.

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

Bạn có thể trích xuất các thành phần riêng lẻ thông qua component:fromDate:

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

Hoặc, thậm chí ngắn gọn hơn, sử dụng NSIntegercon trỏ thông quagetEra:year:month:day:fromDate:

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

Để biết thêm thông tin và ví dụ, hãy xem NSDate Manipulation Made Easy trong iOS 8 . Từ chối trách nhiệm, tôi đã viết bài.


Làm thế nào tôi có thể có được ngày trong năm, ví dụ: 10 tháng 4 là ngày hiện tại là ngày thứ 99 của năm hiện tại ?? -
Nhà phát triển iOS

4

Kể từ iOS 8.0 (và OS X 10), bạn có thể sử dụng phương thức thành phần để đơn giản hóa việc lấy một thành phần ngày duy nhất như vậy:

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

Nên làm cho mọi thứ đơn giản hơn và hy vọng điều này được thực hiện hiệu quả.



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

Điều đó khá rõ ràng không cung cấp cho tôi năm, tháng hoặc ngày dưới dạng số nguyên, đó là những gì tôi yêu cầu trong OP. -1.
Richard J. Ross III

1
Richard J. Ross III: Tôi vừa sửa nó, tôi xin lỗi vì câu trả lời của tôi đã làm mất câu hỏi của bạn.
Linh Nguyễn

2

Đây là giải pháp trong 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

Thử cái này . . .

Đoạn mã:

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

Nó cung cấp cho năm hiện tại, tháng, ngày


1

Hãy thử như sau:

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

Bạn có thể sử dụng nó như

NSDate().currentDateInDayMonthYear()

Đầu ra

6 March 2016

1

Nhanh

Cách dễ dàng hơn để có được bất kỳ yếu tố ngày nào dưới dạng Chuỗi tùy chọn.

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

tôi làm theo cách này ....

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

Để có được chuỗi con người có thể đọc được (ngày, tháng, năm), bạn có thể làm:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *string = [dateFormatter stringFromDate:dateEndDate];
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.