รับ NSDate วันนี้เมื่อวานนี้สัปดาห์ที่แล้วสัปดาห์ที่แล้วเดือนนี้เดือนที่แล้ว…ตัวแปร


86

ฉันพยายามทำคือรับ NSDate วันนี้เมื่อวานนี้สัปดาห์นี้สัปดาห์ที่แล้วเดือนนี้ตัวแปรเดือนที่แล้วพร้อมสำหรับการเปรียบเทียบสำหรับส่วนหัวที่จะเพิ่มในชื่อเรื่องของ UITableView

สิ่งที่ฉันต้องการทำได้ด้วยตนเองในรหัสด้านล่างสำหรับวันที่ 2009-12-11

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

คำตอบ:


93

ดัดแปลงมาจากคู่มือการเขียนโปรแกรมวันที่และเวลา :

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

หากคุณต้องการจำนวนวันที่ถูกต้องโดยขึ้นอยู่กับเดือนคุณควรใช้NSCalendarไฟล์.


77
ค่าคงที่สำหรับเวลาคือ BAD BAD BAD แล้ววันอธิกสุรทินหรืออธิกวินาทีล่ะ? ใช้ NSDateComponents มิฉะนั้นคุณจะประสบปัญหาที่น่ารังเกียจและยากที่จะแก้ไขปัญหาเมื่อตราประทับวันที่ของคุณเริ่มไม่ตรงกัน
Kendall Helmstetter Gelner

11
มันไม่ได้แย่ขนาดนั้นถ้าคุณต้องการโพสต์ที่มีมูลค่าประมาณสัปดาห์ที่แล้วหรืออะไรก็ตาม ฉันระบุว่า OP ควรใช้NSCalendarหากต้องการความถูกต้อง
Ben S

2
ค่าคงที่คงที่จริง ๆ แล้วควรจะใช้ได้ดีสำหรับการนับวัน: ทุกวันคือ 86400 วินาที อธิกวินาทีใช้เวลาเพียงสองเท่า - หนึ่งวันที่มีอธิกวินาทียังคงมี 86400 'วินาที' สำหรับเดือน ... ใช่คัดท้ายชัดเจน :)
คริส

3
@Chris ยกเว้นวันที่ไม่ใช่ 86400 วินาที แล้วเวลาออมแสงล่ะ? ฟังดูไม่สำคัญ แต่สิ่งนี้สามารถนำคุณไปสู่ข้อบกพร่องที่น่ากลัวอย่างมากซึ่งเกิดขึ้นจากที่ใดเมื่อ DST เข้าชมและคุณจำไม่ได้ว่าจะนำมาพิจารณา
jpswain

1
หากคุณต้องการย้อนกลับไปประมาณ 7 วันโดยประมาณคุณสามารถลบเวลาได้ถ้าคุณต้องการกลับไปที่ "วันจันทร์" ของสัปดาห์นี้ให้ใช้ NSCalendar มีกรณีการใช้งานสำหรับทั้งสองสถานการณ์
Johnny Rockex

83

อาจเป็นวิธีที่ดีกว่าในการเขียนสิ่งนี้ แต่นี่คือสิ่งที่ฉันคิดขึ้นจากคำแนะนำ NSCalendar ของ Ben และการทำงานจากที่นั่นไปยัง 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
คุณกำลังทำให้หน่วยความจำรั่วไหลด้วยfromDate:[[NSDate alloc] init]บิตเหล่านั้น
Shaggy Frog

21
@Shaggy Frog: ฉันเดาว่าเขาสมมติว่า ARC เปิดใช้งานอยู่ ... ;)
orj

3
รหัสนี้ทำงานไม่ถูกต้อง ไม่คำนึงถึงเศษส่วนของวินาทีที่เป็นส่วนหนึ่งของวันที่ป้อนข้อมูล กล่าวคือวันที่อาจมี 30.1234 วินาทีและ NSDateComponents มีเพียง 30 เป็นค่าวินาทีดังนั้นการลบ 30 วินาทีจาก NSDate จะทำให้คุณมีเวลา 0.1234 วินาทีหลังจากเที่ยงคืน นอกจากนี้บางวันมีมากกว่า (หรือน้อยกว่า) มากกว่า 24 ชั่วโมง (การออมแสง) ดังนั้นการรับวันที่ของเมื่อวานควรใช้ [องค์ประกอบ setDay: -1] มากกว่า [องค์ประกอบ setHour: -24]
orj

5
@orj FYI, ARC ออกมาทุกยุคทุกสมัยหลังจากโพสต์คำตอบนั้น
Shaggy Frog

3
@orj นอกจากนี้เมื่อเวลาออมแสงเปลี่ยนแปลงการลบชั่วโมงไม่ได้ทำให้คุณเที่ยงคืน -1. รหัสนี้ไม่คุ้มค่า 35 upvotes
Nikolai Ruhe

40

NSDateComponents ยินดีที่จะได้รับในวันนี้:

NSCalendar *cal = [NSCalendar currentCalendar];

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

สิ่งนี้จะสร้าง NSDate ที่มีปีเดือนและวันที่เท่านั้น:

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

หากต้องการรับเมื่อวาน ฯลฯ คุณสามารถคำนวณโดยใช้ NSDateComponents:

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

คุณไม่จำเป็นต้องใส่องค์ประกอบยุคหรือไม่?
Chris Page

ดี. ใช้สิ่งนี้ในการคำนวณวันที่ 8 ปีที่ผ่านมาและทำงานได้ดี เพียงแค่ต้องแก้ไขการรั่วไหลที่นี่: [[NSDateComponents จัดสรร] init];
Craig B

@CraigB ขอบคุณ ไม่ได้หมายความว่าจะเป็นตัวอย่างที่สมบูรณ์ ปล่อยให้การจัดการหน่วยความจำที่ชัดเจนเป็นเรื่องท้าทายสำหรับผู้อ่าน;)
Christian Beer

@ChrisPage องค์ประกอบยุค? เพื่ออะไร?
Christian Beer

1
@ChristianBeer ฉันค่อนข้างมั่นใจว่าต้องพิจารณาส่วนประกอบทั้งหมดที่มีขนาดใหญ่กว่าความละเอียดที่ต้องการ ผมเชื่อว่าควรจะเป็น(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) (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];
}

คุณไม่จำเป็นต้องรวมองค์ประกอบยุคหรือไม่?
Chris Page

ฉันต้องลบ NSDayCalendarUnit และเพิ่ม NSWeekdayCalendarUnit เมื่อคำนวณ DateLastWeek
jessecurry

Apple เปลี่ยนนิยามของ NSWeekdayCalendarUnit และ NSDayCalendarUnit ใน iOS 5.0 วิธีใหม่คือการใช้ NSWeekdayCalendarUnit แต่ในเวอร์ชันเก่าคุณต้องใช้ NSDayCalendarUnit มันเป็นเรื่องยุ่ง ...
Dustin

@Dustin ดูเหมือนว่าจะใช้งานไม่ได้แม้ว่าจะอัปเดตเป็นหน่วยงานใหม่ก็ตาม ... ตัวอย่างเช่นการDateThisWeekตั้งค่าวันธรรมดาจะไม่มีผลกับ NSDate ...
AnthoPak

12

สวิฟต์ 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)

โปรดทราบว่าส่วนประกอบวันที่เป็นทางเลือก


1
@fengd ดีวันนี้ 27 มิ.ย. 2559 เวลา 01.00 น. คือ 28 มิ.ย. 2559 และถ้าลบ 24 ชั่วโมงวันที่ 27 มิ.ย. 1 น. อะไรคือจุดที่ฉันพลาด?
gokhanakkurt

1
ขอโทษ @gokhanakkurt ฉันคิดว่ามีอาการสะอึกในใจ คำตอบของคุณถูกต้อง
fengd

4

คำตอบอื่น ๆ ไม่ได้ผลสำหรับฉัน (อาจเป็นเพราะเขตเวลาของฉัน) นี่คือวิธีที่ฉันทำ:

- (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

หากคุณใช้ iOS 10+ หรือ MacOS 10.12+ คุณสามารถใช้สองCalendarวิธีนี้เพื่อดำเนินการอย่างเหมาะสม

  • func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool = default) -> Date?( เอกสาร )
  • func dateInterval(of component: Calendar.Component, for date: Date) -> DateInterval?( เอกสาร )

นี่คือตัวอย่างวิธีการใช้วิธีการเหล่านี้ใน Swift 3 พร้อมกับผลลัพธ์ของ Playground ในเขตเวลาของฉัน

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

โบนัส: คุณสามารถใช้DateIntervals เพื่อทดสอบว่าวันที่อยู่ในช่วงนั้นหรือไม่ ดำเนินการต่อจากด้านบน:

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

ทำไมจึงyesterdayบอกว่า 29 เม.ย. และnow28 เม.ย.
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

ฉันชอบวัตถุ THCalendarInfo ที่มีอยู่ในโครงการนี้มาก:

http://github.com/jaredholdcroft/kcalendar

ฉันหาต้นฉบับไม่เจอเลย การใช้วัตถุนี้คุณสามารถย้ายไปยังวันก่อนหน้าวันเริ่มต้นสัปดาห์วันเริ่มต้นของเดือนรับวันในสัปดาห์วันของเดือน ... ฯลฯ


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

เนื่องจากทั้งสองอย่างถูกต้องเพื่อรับวันที่ปัจจุบันทั้งสองจึงรวมเวลาด้วย จึงไม่ใช่ทางออกที่ถูกต้องสำหรับคำถาม!
Christian Beer

0

สำหรับตรวจสอบวันที่คือเดือนนี้หรือไม่

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
}

และอันที่สองเปลี่ยนเฉพาะประเภทของ calendarUnit สำหรับจุดอ่อนเช่นนี้

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
}

ฉันหวังว่านี่จะเป็นประโยชน์กับใครบางคนขอบคุณ


0

ฉันตอบคำถามที่คล้ายกันแล้วและนี่คือสาเหตุที่คำตอบของฉันดีกว่า:

  • สวิฟต์ 3 !
  • ใช้ "วันวาน" และ "วันนี้" ของ DateFormatter สิ่งนี้แปลโดย Apple ซึ่งช่วยให้คุณประหยัดงานได้!
  • ใช้สตริง DateComponentsFormatter ที่แปลแล้ว "1 สัปดาห์" (ได้ผลน้อยลงอีกแล้วโดยได้รับความอนุเคราะห์จาก Apple) สิ่งที่คุณต้องทำคือแปลสตริง "% @ ago" 🙂
  • คำตอบอื่น ๆ ไม่ถูกต้องคำนวณเวลาเมื่อวันเปลี่ยนจาก "วันนี้" กับ "เมื่อวานนี้" เพื่อเป็นต้นค่าคงที่คงที่เป็นใหญ่ไม่มีไม่มีเพราะเหตุผล นอกจากนี้คำตอบอื่น ๆ ใช้วันที่ / เวลาปัจจุบันเมื่อควรใช้วันที่ / เวลาของวันปัจจุบัน
  • ใช้ autoupdatingCurrent สำหรับปฏิทินและสถานที่ซึ่งทำให้มั่นใจได้ว่าแอปของคุณจะได้รับการอัปเดตทันทีด้วยปฏิทินและการตั้งค่าภาษาของผู้ใช้ในการตั้งค่าแอป
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.