lấy NSDate hôm nay, hôm qua, Tuần này, Tuần trước, Tháng này, Tháng trước… biến


86

Tôi đang cố gắng để có được NSDate hôm nay, hôm qua, Tuần này, Tuần trước, Tháng này, Tháng trước đã sẵn sàng để so sánh cho các tiêu đề được thêm vào titleForHeaderInSection của UITableView

Những gì tôi muốn được thực hiện theo cách thủ công trong đoạn mã dưới đây cho ngày tháng 12 năm 2009

 NSDate *today = [NSDate dateWithString:@"2009-12-11 00:00:00 +0000"];
 NSDate *yesterday = [NSDate dateWithString:@"2009-12-10 00:00:00 +0000"];
 NSDate *thisWeek = [NSDate dateWithString:@"2009-12-06 00:00:00 +0000"];
 NSDate *lastWeek = [NSDate dateWithString:@"2009-11-30 00:00:00 +0000"];
 NSDate *thisMonth = [NSDate dateWithString:@"2009-12-01 00:00:00 +0000"];
 NSDate *lastMonth = [NSDate dateWithString:@"2009-11-01 00:00:00 +0000"];

Câu trả lời:


93

Phỏng theo Hướng dẫn Lập trình Ngày và Giờ :

// Right now, you can remove the seconds into the day if you want
NSDate *today = [NSDate date];

// All intervals taken from Google
NSDate *yesterday = [today dateByAddingTimeInterval: -86400.0];
NSDate *thisWeek  = [today dateByAddingTimeInterval: -604800.0];
NSDate *lastWeek  = [today dateByAddingTimeInterval: -1209600.0];

// To get the correct number of seconds in each month use NSCalendar
NSDate *thisMonth = [today dateByAddingTimeInterval: -2629743.83];
NSDate *lastMonth = [today dateByAddingTimeInterval: -5259487.66];

Nếu bạn muốn có số ngày chính xác chính xác tùy thuộc vào tháng, bạn nên sử dụng dấu NSCalendar.


77
Hằng số cố định cho thời gian là BAD BAD BAD. Còn ngày nhuận hoặc giây nhuận thì sao? Sử dụng NSDateComponents nếu không bạn SẼ gặp phải một số vấn đề rất khó chịu và khó gỡ lỗi khi tem ngày tháng của bạn bắt đầu không khớp.
Kendall Helmstetter Gelner

11
Nó thực sự không tệ nếu bạn chỉ muốn có giá trị tương đương với các bài đăng của tuần trước hoặc bất cứ điều gì. Tôi chỉ định rằng OP nên sử dụng NSCalendarnếu độ chính xác được yêu cầu.
Ben S

2
Các hằng số cố định thực sự chỉ ổn khi đếm ngày: mỗi ngày là 86400 giây. Giây nhuận đơn giản dài gấp đôi - một ngày có giây nhuận vẫn có 86400 'giây'. Đối với nhiều tháng ... vâng chỉ đạo rõ ràng :)
Chris

3
@Chris ngoại trừ những ngày không phải 86400 giây. Điều gì về thời gian tiết kiệm ánh sáng ban ngày? Nghe có vẻ không đáng kể, nhưng điều này thực sự có thể dẫn bạn đến những lỗi siêu khủng khiếp không biết từ đâu đến khi DST xảy ra và bạn không nhớ đã tính đến nó.
jpswain

1
Nếu bạn chỉ muốn quay lại khoảng 7 ngày, bạn có thể trừ đi thời gian, nếu bạn muốn quay lại 'Thứ Hai' của tuần này, hãy sử dụng NSCalendar. Có những trường hợp sử dụng cho cả hai trường hợp.
Johnny Rockex

83

Có thể là một cách tốt hơn để viết điều này nhưng đây là những gì tôi đã đưa ra trên đề xuất NSCalendar của Ben và làm việc từ đó cho NSDateComponents

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond ) fromDate:[[NSDate alloc] init]];

[components setHour:-[components hour]];
[components setMinute:-[components minute]];
[components setSecond:-[components second]];
NSDate *today = [cal dateByAddingComponents:components toDate:[[NSDate alloc] init] options:0]; //This variable should now be pointing at a date object that is the start of today (midnight);

[components setHour:-24];
[components setMinute:0];
[components setSecond:0];
NSDate *yesterday = [cal dateByAddingComponents:components toDate: today options:0];

components = [cal components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:[[NSDate alloc] init]];

[components setDay:([components day] - ([components weekday] - 1))]; 
NSDate *thisWeek  = [cal dateFromComponents:components];

[components setDay:([components day] - 7)];
NSDate *lastWeek  = [cal dateFromComponents:components];

[components setDay:([components day] - ([components day] -1))]; 
NSDate *thisMonth = [cal dateFromComponents:components];

[components setMonth:([components month] - 1)]; 
NSDate *lastMonth = [cal dateFromComponents:components];

NSLog(@"today=%@",today);
NSLog(@"yesterday=%@",yesterday);
NSLog(@"thisWeek=%@",thisWeek);
NSLog(@"lastWeek=%@",lastWeek);
NSLog(@"thisMonth=%@",thisMonth);
NSLog(@"lastMonth=%@",lastMonth);

13
Bạn đang làm rò rỉ bộ nhớ với những fromDate:[[NSDate alloc] init]bit đó.
Shaggy Frog

21
@Shaggy Frog: Tôi đoán anh ấy đang giả sử ARC được bật ...;)
orj

3
Mã này không hoạt động chính xác. Nó không tính đến phần nhỏ của giây là một phần của ngày nhập. Tức là, ngày có thể có 30.1234 giây và NSDateComponents chỉ có 30 là giá trị giây, vì vậy trừ đi 30 giây từ NSDate, bạn sẽ có 0,1234 giây sau nửa đêm. Ngoài ra, một số ngày có nhiều hơn (hoặc ít hơn) 24 giờ (tiết kiệm ánh sáng ban ngày), vì vậy việc xác định ngày hôm qua thực sự nên sử dụng [thành phần setDay: -1] hơn là [thành phần setHour: -24].
orj

5
@orj FYI, ARC ra đời sau khi câu trả lời đó được đăng
Shaggy Frog

3
@orj Ngoài ra, khi thời gian tiết kiệm ánh sáng ban ngày thay đổi, trừ đi số giờ không cho bạn nửa đêm. -1. Mã này không có giá trị 35 lượt ủng hộ.
Nikolai Ruhe

40

NSDateComponents thật tuyệt khi có được ngày hôm nay:

NSCalendar *cal = [NSCalendar currentCalendar];

NSDate *date = [NSDate date];
NSDateComponents *comps = [cal components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) 
                                                          fromDate:date];
NSDate *today = [cal dateFromComponents:comps];

Điều này tạo NSDate chỉ có năm, tháng và ngày:

(gdb) po today
2010-06-22 00:00:00 +0200

Để có được ngày hôm qua, v.v. bạn có thể tính toán nó bằng cách sử dụng NSDateComponents:

NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:-1];
NSDate *yesterday = [cal dateByAddingComponents:components toDate:today options:0];

Bạn không cần phải bao gồm thành phần thời đại?
Chris Page

Đẹp. Đã sử dụng nó để tính toán một ngày trong 8 năm trước và nó hoạt động rất tốt. Chỉ cần sửa lỗi rò rỉ ở đây: [[NSDateComponents CẤP] init];
Craig B

@CraigB cảm ơn. Nó không phải là một ví dụ hoàn chỉnh. Bỏ qua việc quản lý bộ nhớ rõ ràng như một thách thức đối với người đọc;)
Christian Bia

@ChrisPage thành phần thời đại? Để làm gì?
Bia Christian vào

1
@ChristianBeer Tôi khá chắc chắn rằng tất cả các thành phần lớn hơn độ phân giải mong muốn phải được xem xét. Tôi tin là (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)nên như vậy (NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit).
Chris Page

19
+ (NSDate*)dateFor:(enum DateType)dateType {

    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDateComponents *comps =
    [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
                fromDate:[NSDate date]];

    if(dateType == DateYesterday) {

        comps.day--;
    }
    else if(dateType == DateThisWeek) {

        comps.weekday = 1;
    }
    else if(dateType == DateLastWeek) {

        comps.weekday = 1;
        comps.week--;
    }
    else if(dateType == DateThisMonth) {

        comps.day = 1;
    }
    else if(dateType == DateLastMonth) {

        comps.day = 1;
        comps.month--;
    }
    else if(dateType != DateToday)
        return nil;

    return [calendar dateFromComponents:comps];
}

Bạn không cần phải bao gồm thành phần thời đại?
Chris Page

Tôi đã phải xóa NSDayCalendarUnit và thêm NSWeekdayCalendarUnit khi tính toán DateLastWeek.
jessecurry

Apple đã thay đổi định nghĩa của NSWeekdayCalendarUnit và NSDayCalendarUnit xung quanh iOS 5.0. Cách mới là sử dụng NSWeekdayCalendarUnit. Nhưng trên các phiên bản cũ hơn, bạn phải sử dụng NSDayCalendarUnit. Đó là một mớ hỗn độn ...
Dustin

@Dustin Nó dường như không hoạt động, ngay cả khi cập nhật lên các đơn vị mới ... Ví dụ: DateThisWeekđặt ngày trong tuần không ảnh hưởng đến NSDate ...
AnthoPak

11

Swift 4.2

let today = Date()
let yesterday = today.addingTimeInterval(-86400.0)
let thisWeek = today.addingTimeInterval(-604800.0)
let lastWeek = today.addingTimeInterval(-1209600.0)

let thisMonth = today.addingTimeInterval(-2629743.83)
let lastMonth = today.addingTimeInterval(-5259487.66)

// components of the date
let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
let components = calendar.dateComponents([.year, .month, .day], from: today)
let (year, month, day) = (components.year, components.month, components.day)

Xin lưu ý rằng các thành phần ngày là tùy chọn.


1
@fengd à, hôm nay ngày 27 tháng 6 năm 2016, lúc 1 giờ sáng thì ngày 28 tháng 6 năm 2016, và nếu tôi trừ đi 24 giờ, ngày sẽ là ngày 27 tháng 6 1 giờ sáng. Điểm mà tôi đã bỏ lỡ là gì?
gokhanakkurt

1
xin lỗi, @gokhanakkurt. Tôi nghĩ rằng đã có một số trục trặc trong tâm trí tôi. câu trả lời của bạn là đúng
Fengd

4

Các câu trả lời khác không phù hợp với tôi (có thể do múi giờ của tôi). Đây là cách tôi làm điều đó:

- (BOOL)isOnThisWeek:(NSDate *)dateToCompare
{
    NSCalendar * calendar = [NSCalendar currentCalendar];
    NSDate     * today    = [NSDate date];

    int todaysWeek        = [[calendar components: NSWeekCalendarUnit fromDate:today] week];
    int dateToCompareWeek = [[calendar components: NSWeekCalendarUnit fromDate:dateToCompare] week];

    int todaysYear         = [[calendar components:NSYearCalendarUnit fromDate:today] year];
    int dateToCompareYear  = [[calendar components:NSYearCalendarUnit fromDate:dateToCompare] year];

    if (todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear) {
        return YES;
    }

    return NO;
}

4

Nếu đang sử dụng iOS 10+ hoặc MacOS 10.12+, bạn có thể sử dụng hai Calendarphương pháp này để thực hiện việc này đúng cách.

  • func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool = default) -> Date?( tài liệu )
  • func dateInterval(of component: Calendar.Component, for date: Date) -> DateInterval?( tài liệu )

Đây là một ví dụ về cách sử dụng các phương pháp này trong Swift 3, cùng với đầu ra của sân chơi theo múi giờ của tôi.

let calendar = Calendar.current
let now = Date()
// => "Apr 28, 2017, 3:33 PM"

let yesterday = calendar.date(byAdding: .day, value: -1, to: now)
// => "Apr 29, 2017, 3:33 PM"
let yesterdayStartOfDay = calendar.startOfDay(for: yesterday!)
// => ""Apr 29, 2017, 12:00 AM"

let thisWeekInterval = calendar.dateInterval(of: .weekOfYear, for: now)
// => 2017-04-23 04:00:00 +0000 to 2017-04-30 04:00:00 +0000

let thisMonthInterval = calendar.dateInterval(of: .month, for: now)
// => 2017-04-01 04:00:00 +0000 to 2017-05-01 04:00:00 +0000

let aDateInLastWeek = calendar.date(byAdding: .weekOfYear, value: -1, to: now)
let lastWeekInterval = calendar.dateInterval(of: .weekOfYear, for: aDateInLastWeek!)
// => 2017-04-16 04:00:00 +0000 to 2017-04-23 04:00:00 +0000

let aDateInLastMonth = calendar.date(byAdding: .month, value: -1, to: now)
let lastMonthInterval = calendar.dateInterval(of: .weekOfYear, for: aDateInLastMonth!)
// => 2017-03-26 04:00:00 +0000 to 2017-04-02 04:00:00 +0000

Phần thưởng: Bạn có thể sử dụng các DateIntervals để kiểm tra xem một ngày có nằm trong phạm vi đó hay không. Tiếp tục từ phía trên:

thisWeekInterval!.contains(now)
// => true
lastMonthInterval!.contains(now)
// => false

Tại sao nó yesterdaynói là 29 tháng 4 và nownói là 28 tháng 4?
Juan Boero

1
NSDate *today = [NSDate date]; // Today's date
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents =[gregorian componentsNSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:today];
NSInteger day = [weekdayComponents day];

0

Tôi thực sự thích đối tượng THCalendarInfo có trong dự án này:

http://github.com/jaredholdcroft/kcalendar

Tôi hoàn toàn không thể tìm thấy bản gốc. Sử dụng đối tượng này, bạn có thể di chuyển đến một ngày trước đó, bắt đầu một tuần, bắt đầu một tháng, lấy ngày trong tuần, ngày trong tháng ... vv.


0
NSDate *today = [[NSDate alloc] initWithTimeIntervalSinceNow:0];

14
Tại sao không [NSDate date]?
joshpaul

Vì cả hai đều có giá trị để lấy ngày hiện tại nên cả hai đều bao gồm thời gian. Vì vậy, nó không phải là giải pháp chính xác cho câu hỏi!
Bia Cơ đốc

0

Cái này để kiểm tra ngày có phải là tháng này hay không

func isOnThisMonth(dateToCompare: NSDate) -> Bool {
    let calendar: NSCalendar = NSCalendar.currentCalendar()
    let today: NSDate = NSDate()
    let todaysWeek: Int = calendar.components(NSCalendarUnit.Month, fromDate: today).month
    let dateToCompareWeek: Int = calendar.components(.Month, fromDate: dateToCompare).month
    let todaysYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: today).year
    let dateToCompareYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: dateToCompare).year
    if todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear {
        return true
    }
    return false
}

Và cái thứ hai chỉ thay đổi loại lịchUnit cho yếu như thế này

func isOnThisWeek(dateToCompare: NSDate) -> Bool {
    let calendar: NSCalendar = NSCalendar.currentCalendar()
    let today: NSDate = NSDate()
    let todaysWeek: Int = calendar.components(NSCalendarUnit.Weekday, fromDate: today).weekday
    let dateToCompareWeek: Int = calendar.components(.Weekday, fromDate: dateToCompare).weekday
    let todaysYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: today).year
    let dateToCompareYear: Int = calendar.components(NSCalendarUnit.Year, fromDate: dateToCompare).year
    if todaysWeek == dateToCompareWeek && todaysYear == dateToCompareYear {
        return true
    }
    return false
}

Tôi hy vọng điều này là hữu ích cho ai đó Cảm ơn.


0

Tôi trả lời một câu hỏi tương tự đã và đây là lý do tại sao câu trả lời của tôi là tốt hơn:

  • Swift 3 !
  • Sử dụng "Hôm qua" và "Hôm nay" của DateFormatter. Điều này đã được Apple dịch, giúp bạn tiết kiệm công việc!
  • Sử dụng chuỗi "1 tuần" đã được dịch của DateComponentsFormatter. (Một lần nữa, ít công việc hơn cho bạn, do Apple cung cấp.) Tất cả những gì bạn phải làm là dịch chuỗi "% @ ago". 🙂
  • Các câu trả lời khác tính toán sai thời gian khi ngày chuyển từ "hôm nay" sang "hôm qua" thành vv Hằng số cố định là một KHÔNG-KHÔNG lớn vì lý do . Ngoài ra, các câu trả lời khác sử dụng ngày / giờ hiện tại khi chúng nên sử dụng cuối ngày / giờ hiện tại.
  • Sử dụng autoupdatingCurrent cho Lịch & Ngôn ngữ để đảm bảo ứng dụng của bạn được cập nhật ngay lập tức với lịch và tùy chọn ngôn ngữ của người dùng trong Settings.app
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.