【问题标题】:get NSDate today, yesterday, this Week, last Week, this Month, last Month... variables获取 NSDate 今天、昨天、本周、上周、本月、上个月……变量
【发布时间】:2010-12-25 17:45:44
【问题描述】:

我想做的是让 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"];

【问题讨论】:

    标签: iphone time comparison nsdate


    【解决方案1】:

    改编自Date and Time Programming Guide

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

    【讨论】:

    • 时间的固定常数是 BAD BAD BAD。闰日或闰秒呢?使用 NSDateComponents,否则当您的日期戳开始不匹配时,您将遇到一些非常讨厌且难以调试的问题。
    • 如果您只想要大约上周的帖子或其他内容,那真的没那么糟糕。如果需要精确性,我指定 OP 应使用 NSCalendar
    • 固定常量实际上应该可以计算天数:每天是 86400 秒。闰秒只需要两倍的时间 - 闰秒的一天仍然有 86400 '秒'。至于几个月...是的,请避开:)
    • @Chris 除非天数不是 86400 秒。夏令时呢?这听起来微不足道,但这实际上会导致您遇到超级粗糙的错误,这些错误会在 DST 来袭时不知从何而来,而您却不记得将其考虑在内。
    • 如果你只想回到大约7天,你可以减去时间,如果你想回到本周的'星期一',使用NSCalendar。这两种情况都有用例。
    【解决方案2】:

    可能是写这篇文章的更好方法,但在这里我提出了 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);
    

    【讨论】:

    • 那些fromDate:[[NSDate alloc] init] 位正在泄漏内存。
    • @Shaggy Frog:我猜他是在假设 ARC 已启用... ;)
    • 此代码无法正常工作。它不考虑作为输入日期一部分的秒的小数部分。即,日期可能有 30.1234 秒,而 NSDateComponents 只有 30 作为秒值,因此从 NSDate 中减去 30 秒后,您会在午夜过后剩下 0.1234 秒。此外,有些日子的时间多于(或少于)24 小时(夏令时),因此获取昨天的日期应该真正使用 [components setDay:-1] 而不是 [components setHour:-24]。
    • @orj 仅供参考,ARC 在发布该答案后很长时间才出现
    • @orj 此外,在夏令时更改时,减去小时数不会给你午夜。 -1。此代码不值得 35 次投票。
    【解决方案3】:

    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];
    • @CraigB 谢谢。这并不是一个完整的例子。忽略了明显的内存管理作为读者的挑战;)
    • @ChrisPage 时代组件?干什么用的?
    • @ChristianBeer 我很确定必须考虑所有大于所需分辨率的组件。我相信(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) 应该是(NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
    【解决方案4】:
    + (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。
    • Apple 在 iOS 5.0 前后更改了 NSWeekdayCalendarUnit 和 NSDayCalendarUnit 的定义。新方法是使用 NSWeekdayCalendarUnit。但在旧版本上,您必须使用 NSDayCalendarUnit。真是一团糟……
    • @Dustin 这似乎不起作用,即使更新到新单位...例如对于DateThisWeek,设置工作日对 NSDate 没有影响...
    【解决方案5】:

    斯威夫特 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)
    

    请注意,日期组件是可选的。

    【讨论】:

    • @fengd 好吧,今天 2016 年 6 月 27 日凌晨 1 点,日期将是 2016 年 6 月 28 日,如果我减去 24 小时,日期将是 6 月 27 日凌晨 1 点。我错过了什么?
    • 对不起,@gokhanakkurt。我想我的脑子里有些打嗝。你的答案是正确的
    【解决方案6】:

    其他答案对我不起作用(可能是因为我的时区)。我就是这样做的:

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

    【讨论】:

      【解决方案7】:

      如果您使用的是 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 中使用这些方法的示例,以及我所在时区的 Playgrounds 输出。

      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 说是 4 月 29 日,now 说是 4 月 28 日?
      【解决方案8】:
      NSDate *today = [NSDate date]; // Today's date
      NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
      NSDateComponents *weekdayComponents =[gregorian componentsNSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:today];
      NSInteger day = [weekdayComponents day];
      

      【讨论】:

        【解决方案9】:

        我真的很喜欢这个项目中包含的 THCalendarInfo 对象:

        http://github.com/jaredholdcroft/kcalendar

        我找不到原版。使用此对象,您可以移动到前一天、一周的开始、一个月的开始、获取一周中的某一天、一个月中的某一天……等等等等。

        【讨论】:

          【解决方案10】:
          NSDate *today = [[NSDate alloc] initWithTimeIntervalSinceNow:0];
          

          【讨论】:

          • 由于两者都可以获取当前日期,因此都包含时间。所以这不是问题的正确解决方案!
          【解决方案11】:

          这是为了检查日期是不是这个月

          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
          }
          

          我希望这对某人有帮助谢谢。

          【讨论】:

            【解决方案12】:

            我回答了一个类似的问题already,这就是为什么我的回答更好:

            • 斯威夫特 3
            • 利用 DateFormatter 的“昨天”和“今天”。这已经由 Apple 翻译了,这样可以节省您的工作量!
            • 使用 DateComponentsFormatter 已翻译的“1 周”字符串。 (再次为您减少工作量,由 Apple 提供。)您所要做的就是翻译“%@ ago”字符串。 ?
            • 其他答案错误地计算了一天从“今天”切换到“昨天”到等的时间。固定常量是一个很大的 NO-NO,因为reasons。此外,其他答案使用当前日期/时间,而他们应该使用当天的结束日期/时间。
            • 对日历和区域设置使用 autoupdatingCurrent,以确保您的应用立即与 Settings.app 中用户的日历和语言首选项保持同步

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-03-19
              • 2011-08-17
              • 2013-05-07
              • 2020-05-18
              • 2012-12-12
              • 2011-07-14
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多