今天,昨天,本周,上周,本月,上个月获取NSDate ...变量


86

我想做的就是获取NSDate,今天,昨天,本周,上周,本月,上月准备好比较变量,以便在UITableView的titleForHeaderInSection中添加标头

我想要的是在以下代码中手动完成的,日期为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"];

Answers:


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。leap日或leap秒呢?使用NSDateComponents,否则当您的日期戳开始不匹配时,您将遇到一些非常讨厌且难以调试的问题。
Kendall Helmstetter Gelner 2009年

11
如果您只想要大约上周的帖子或其他内容,那的确不是那么糟糕。我指定NSCalendar如果需要准确性,则应该使用OP 。
本S

2
固定常数实际上对于计算天数应该是正确的:每天为86400秒。seconds秒只需花费两倍的时间-a秒的一天仍然有86400个“秒”。至于几个月...是的,请避开:)
克里斯(Chris

3
@Chris,除非天数不是86400秒。夏令时呢?听起来微不足道,但这实际上可能会导致您遇到超级粗糙的错误,这些错误会在DST命中时突然出现,并且您不记得要考虑到它了。
jpswain

1
如果您只想返回大约7天,则可以减去时间,如果您想返回本周的“星期一”,请使用NSCalendar。两种方案都有用例。
约翰尼·洛克克斯

83

可能是写这个的更好的方法,但是在这里我提出了Ben的NSCalendar建议,然后从那里工作到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]位将导致内存泄漏。
蓬松的青蛙,

21
@Shaggy青蛙:我猜他是假设ARC启用...;)
ORJ

3
此代码无法正常工作。它没有考虑到输入日期所占的几分之一秒。即,日期可能有30.1234秒,而NSDateComponents仅具有30作为秒值,因此从NSDate减去30秒将使您午夜过后0.1234秒。此外,有些日子比夏令时多(或少于24小时),因此获取昨天的日期应该真正使用[components setDay:-1]而不是[components setHour:-24]。
orj 2012年

5
@orj仅供参考,ARC在发布答案后出现了很长时间
Shaggy Frog

3
@orj另外,在夏时制更改时,减去小时数不会使您午夜。-1。此代码不值得35票赞成。
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];

您不需要包括时代部分吗?
克里斯·佩奇

真好 用它来计算过去8年的日期,效果很好。只需在这里修复泄漏:[[NSDateComponents alloc] 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];
}

您不需要包括时代部分吗?
克里斯·佩奇

在计算DateLastWeek时,我必须删除NSDayCalendarUnit并添加NSWeekdayCalendarUnit。
jessecurry 2011年

苹果在iOS 5.0左右更改了NSWeekdayCalendarUnit和NSDayCalendarUnit的定义。新方法是使用NSWeekdayCalendarUnit。但是在旧版本上,您必须使用NSDayCalendarUnit。真是一团糟...
达斯汀

@Dustin即使更新到新的单位,它似乎也不起作用...例如DateThisWeek,设置工作日对NSDate没有影响……
AnthoPak

11

斯威夫特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好,今天是2016年6月27日,凌晨1点将是2016年6月28日,如果我减去24小时,日期将是6月27日凌晨1点。我错过了什么呢?
gokhanakkurt

1
抱歉,@ gokhanakkurt。我认为我有些打h。您的答案是正确的
-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?docs
  • func dateInterval(of component: Calendar.Component, for date: Date) -> DateInterval?docs

这是一个如何在Swift 3中使用这些方法的示例,以及我所在时区的游乐场输出。

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

奖励:您可以使用DateInterval来测试日期是否在该范围内。从上面继续:

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

为什么yesterday说4月29日和now4月28日?
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
NSDate *today = [[NSDate alloc] initWithTimeIntervalSinceNow:0];

14
为什么不[NSDate date]呢?
joshpaul 2011年

由于两者都可以有效获取当前日期,因此两者都包含时间。因此,这不是该问题的正确解决方案!
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
}

第二个只更改日历单元的类型为弱

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,以确保您的应用立即与Settings.app中用户的日历和语言首选项保持最新。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.