【问题标题】:NSCalendar first day of weekNSCalendar 一周的第一天
【发布时间】:2010-11-09 13:36:57
【问题描述】:

有谁知道是否有办法在 NSCalendar 上设置一周的第一天,或者是否有一个日历已经将星期一作为一周的第一天,而不是星期日。 我目前正在开发一个基于一周工作量的应用程序,它需要从星期一开始,而不是星期天。我很可能会做一些工作来解决这个问题,但会有很多极端情况。我希望平台为我做这件事。

提前致谢

这是我正在使用的一些代码。现在是星期六,所以我希望工作日是 6,而不是 7。这意味着星期日将是 7,而不是滚动到 0

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setFirstWeekday:0];
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit;
NSDateComponents *todaysDate = [gregorian components:unitFlags fromDate:[NSDate date]];
int dayOfWeek = todaysDate.weekday;

【问题讨论】:

  • 那么您找到解决方案了吗?我也有同样的感受!
  • ISO 8601 日历的第一个工作日似乎默认设置为星期一。

标签: iphone cocoa calendar weekday nscalendar


【解决方案1】:

编辑:这不会检查上个月开始的边缘情况。一些更新的代码来涵盖这一点:https://stackoverflow.com/a/14688780/308315


如果有人还在关注这个,你需要使用

ordinalityOfUnit:inUnit:forDate:

并将 firstWeekday 设置为 2。(1 == 星期日和 7 == 星期六)

代码如下:

NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
[gregorian setFirstWeekday:2]; // Sunday == 1, Saturday == 7
NSUInteger adjustedWeekdayOrdinal = [gregorian ordinalityOfUnit:NSWeekdayCalendarUnit inUnit:NSWeekCalendarUnit forDate:[NSDate date]];
NSLog(@"Adjusted weekday ordinal: %d", adjustedWeekdayOrdinal);

请记住,工作日的序数从一周的第一天的 1 开始,而不是零。

Documentation link.

【讨论】:

  • 很好的答案,这是真正的交易!
  • 同上。很好的答案,这是要走的路!
  • @Joshua 这是正确答案,请确认并勾选答案。
  • 出于某种原因,在执行以下操作时:[gregorian components:NSYearForWeekOfYearCalendarUnit |NSYearCalendarUnit | NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:date]; 其中日期是星期天的日期,comps.weekday 返回 1 而不是 7...有什么线索吗?
【解决方案2】:

此代码构造了一个设置为本周星期一的日期:

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

NSDate *today = [NSDate date];
NSDate *beginningOfWeek = nil;
BOOL ok = [gregorian rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek
                                interval:NULL forDate: today];

【讨论】:

  • 这个(考虑到mmc的回答)确实有效。
  • 如果 Joshua 先生把答案检查放在这里就好了,因为它完全符合问题的描述。
  • -1 因为这实际上将 beginOfWeek 设置为星期日上午 12 点。
【解决方案3】:

setFirstWeekday: 在 NSCalendar 对象上。 为接收者设置第一个工作日的索引。

- (void)setFirstWeekday:(NSUInteger)weekday

应该做的伎俩。

【讨论】:

  • 我尝试将此值设置为各种值,它对 NSCalendary 的 weekday 属性没有影响。我在我的原始帖子中添加了一些代码,这样你就可以看到我在做什么。谢谢
  • 对不起,我指的是 NSDateComponents 上的 weekday 属性
【解决方案4】:

在我看来,此设置应根据用户区域设置是动态的。 因此应该使用:

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setLocale:[NSLocale currentLocale]];

这将导致日历根据用户区域自动设置第一周。除非您为特定目的/用户区域设置开发应用程序(或者更愿意让用户选择这一天)。

【讨论】:

  • +1 - 这真的是个人喜好问题 - 尽管世界上大多数人都使用星期一作为一周的开始(实际上是 ISO 标准),来自美国,我已经习惯了周日开始。为什么不使用这个优雅的答案并依靠用户自己的日历设置呢?这个解决方案非常适合我的应用。
  • -1 - 问题是明确要求将开始日期更改为星期一的方法,并且 stackoverflow 的范围主要包括代码解决方案,而不是最佳应用程序实践。无论如何,这应该是对主线程的评论,而不是“回答”帖子。
【解决方案5】:

我已经这样做了。

NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *today = [NSDate date];
NSDateComponents *compForWeekday = [gregorian components:(NSWeekdayCalendarUnit) fromDate:today];
NSInteger weekDayAsNumber = [compForWeekday weekday]; // The week day as number but with sunday starting as 1

weekDayAsNumber = ((weekDayAsNumber + 5) % 7) + 1; // Transforming so that monday = 1 and sunday = 7

【讨论】:

    【解决方案6】:

    我在这里的很多答案都遇到了麻烦。 .也许只是我。 .

    这是一个适合我的答案:

    - (NSDate*)firstDayOfWeek
    {
        NSCalendar* cal = [[NSCalendar currentCalendar] copy];
        [cal setFirstWeekday:2]; //Override locale to make week start on Monday
        NSDate* startOfTheWeek;
        NSTimeInterval interval;
        [cal rangeOfUnit:NSWeekCalendarUnit startDate:&startOfTheWeek interval:&interval forDate:self];
        return startOfTheWeek;
    }
    
    - (NSDate*)lastDayOfWeek
    {
        NSCalendar* cal = [[NSCalendar currentCalendar] copy];
        [cal setFirstWeekday:2]; //Override locale to make week start on Monday
        NSDate* startOfTheWeek;
        NSTimeInterval interval;
        [cal rangeOfUnit:NSWeekCalendarUnit startDate:&startOfTheWeek interval:&interval forDate:self];
        return [startOfTheWeek dateByAddingTimeInterval:interval - 1];
    }
    

    更新:

    正如@vikingosegundo 所指出的(elsewhere),通常最好让当地人确定哪一天是一周的开始,但是在这种情况下,OP 要求一周的开始发生在星期一,因此我们复制系统日历,并覆盖 firstWeekDay。

    【讨论】:

    • -1 将倍数 86,400 添加到日期绝不是正确的答案。
    • 在这里通过一个新问题要求澄清:stackoverflow.com/questions/19826952/…
    • 学究式:lastDayOfTheWeek 将返回一周的最后一秒。
    • 重命名是一个聪明的解决方案
    • 实际上您的答案与此答案非常相似:stackoverflow.com/a/1835499/106435 包括 OP 明确需要将本周开始设置为星期一的相同缺陷。这不在您的答案中。只是说,在调用该方法之前,您希望日历被更改为 [[NSCalendar currentCalendar] setFirstWeekday: 2];// Sunday == 1, Saturday == 7
    【解决方案7】:

    Kris 的答案的问题是一周开始于上个月的边缘情况。这是一些更简单的代码,它还检查边缘情况:

    // Finds the date for the first day of the week
    - (NSDate *)getFirstDayOfTheWeekFromDate:(NSDate *)givenDate
    {
        NSCalendar *calendar = [NSCalendar currentCalendar];
    
        // Edge case where beginning of week starts in the prior month
        NSDateComponents *edgeCase = [[NSDateComponents alloc] init];
        [edgeCase setMonth:2];
        [edgeCase setDay:1];
        [edgeCase setYear:2013];
        NSDate *edgeCaseDate = [calendar dateFromComponents:edgeCase];
    
        NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:edgeCaseDate];
        [components setWeekday:1]; // 1 == Sunday, 7 == Saturday
        [components setWeek:[components week]];
    
        NSLog(@"Edge case date is %@ and beginning of that week is %@", edgeCaseDate , [calendar dateFromComponents:components]);
    
        // Find Sunday for the given date
        components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:givenDate];
        [components setWeekday:1]; // 1 == Sunday, 7 == Saturday
        [components setWeek:[components week]];
    
        NSLog(@"Original date is %@ and beginning of week is %@", givenDate , [calendar dateFromComponents:components]);
    
        return [calendar dateFromComponents:components];
    }
    

    【讨论】:

    • 这不适用于一个角落。对于日期 2012-12-31,它返回:2012-01-01
    • 我应该澄清一下,我将工作日设置为 2(星期一)。
    【解决方案8】:

    我在其他消息中看到了误解。第一个工作日(无论是哪一个)的编号为 1 而不是 0。默认情况下,Sunday=1,如“Cocoa 日期和时间编程指南简介:日历计算”中所示:

    "公历中星期日的工作日值为 1"

    对于星期一作为第一个工作日,我唯一的补救办法是使用蛮力条件来修复计算

    NSCalendar *cal=[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *comps = [cal components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
    // set to 7 if it's Sunday otherwise decrease weekday number
    NSInteger weekday=[comps weekday]==1?7:[comps weekday]-1; 
    

    【讨论】:

      【解决方案9】:

      下面还包括边缘情况,

      - (NSDate *)getFirstDayOfTheWeekFromDate:(NSDate *)givenDate
      {
          NSCalendar *calendar = [NSCalendar currentCalendar];
      
      
         NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:givenDate];
          [components setWeekday:2]; // 1 == Sunday, 7 == Saturday
          if([[calendar dateFromComponents:components] compare: curDate] == NSOrderedDescending) // if start is later in time than end
          {
              [components setWeek:[components week]-1];
          }
      
          return [calendar dateFromComponents:components];
      }
      

      【讨论】:

        【解决方案10】:

        您只需更改日历的.firstWeekday。

        NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
        calendar.firstWeekday = 2;
        

        然后用rangeOfUnit:startDate:interval:forDate:得到第一天

        NSDate *startOfWeek;
        [calendar rangeOfUnit:NSCalendarUnitWeekOfYear startDate:&startOfWeek interval:nil forDate:[NSdate date]];
        

        【讨论】:

          【解决方案11】:

          试试这个:

          NSCalendar *yourCal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]
          [yourCal setFirstWeekday:0];
          

          【讨论】:

          • 星期一应该是setFirstWeekday:2
          【解决方案12】:

          我找到了使用 nscalender 显示任何工作日名称的方法..使用以下代码.. 只需从 xcode 菜单栏打开控制台即可查看结果。将以下代码复制粘贴到 viewDidLoad 方法中即可获取一周的第一天

          NSDate *today = [NSDate date];
          NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
          [dateFormat setDateFormat:@"MM/dd/yyyy :EEEE"];
          NSString *dateString = [dateFormat stringFromDate:today];
          NSLog(@"date: %@", dateString);
          [dateFormat release];
          NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
          
          NSDateComponents *components = [gregorian components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:today];
          [components setDay:([components day]-([components weekday]-1))];
          
          NSDate *beginningOfWeek = [gregorian dateFromComponents:components];
          NSDateFormatter *dateFormat_first = [[NSDateFormatter alloc] init];
          [dateFormat_first setDateFormat:@"MM/dd/yyyy :EEEE"];
          NSString *dateString_first = [dateFormat_first stringFromDate:beginningOfWeek];
          NSLog(@"First_date: %@", dateString_first);
          

          输出将是:

           date: 02/11/2010 :Thursday
           First_date: 02/07/2010 :Sunday
          

          自从我在 2010 年 2 月 11 日运行此程序以来,您将根据当前日期获得所需的输出。

          同样,如果您想获得一周的第一个工作日,即星期一的日期,那么只需稍微修改一下代码:

          更改:[components setDay:([components day]-([components weekday]-1))];

          到 [components setDay:([components day]-([components weekday]-2))];

          获取该周的星期一日期..

          同样,您可以尝试通过更改整数 -1、-2 等来查找七个工作日中的任何一个的日期...

          希望你的问题得到解答..

          谢谢, 邦森迪亚斯

          【讨论】:

          • 我想过这个解决方案,但它不能正常工作。对于 2001 年 1 月 2 日星期日,它将返回 2011 年 1 月 3 日星期一,但应该改为 2010 年 12 月 27 日星期一返回。
          【解决方案13】:

          ISO 8601 日历的第一个工作日似乎默认设置为星期一。

          【讨论】:

          • 似乎不是真的 - 星期天的值仍然是 1
          • 星期天显然是 1。我的意思是,在实例化 ISO 8601 日历时,第一个工作日应该默认设置为星期一,也就是 2。
          • 抱歉,@Christian Schnorr,你能解释一下 - 2 - 星期一吗?应该是 1 - 星期一。
          • 这些索引从 1 开始,而不是 0。
          【解决方案14】:

          使用日历nextWeekend(iOS 10 或更高版本)和ordinality(感谢@kris-markel)。我已将星期一作为 en_US 日历的第一周。

          这是一个回退到 firstWeekday 的示例:

          extension Calendar {
              var firstWorkWeekday: Int {
                  guard #available(iOS 10.0, *) else{
                      return self.firstWeekday
                  }
                  guard let endOfWeekend = self.nextWeekend(startingAfter: Date())?.end else {
                      return self.firstWeekday
                  }
                  return self.ordinality(of: .weekday, in: .weekOfYear, for: endOfWeekend) ?? self.firstWeekday
              }
          }
          

          【讨论】:

            【解决方案15】:

            Swift 解决方案(注意,使用 .yearForWeekOfYear,而不是 .year):

            let now = Date()
            let cal = Calendar.current
            var weekComponents = cal.dateComponents([.yearForWeekOfYear, .weekOfYear,
                                                     .weekday], from: now)
            //weekComponents.weekday = 1  // if your week starts on Sunday
            weekComponents.weekday = 2  // if your week starts on Monday
            cal.date(from: weekComponents) // returns date with first day of the week
            

            【讨论】:

            • 可以更简单。只需省略 .weekday 组件,您就可以通过 ISO 8601(星期一)获得当前一周的开始日期。
            • 注意,API (macOS 10.14.6) 中也有一个错误,如果你使用工作日 1(2 或 nil 或好的),你必须从 weekOfYear 中减去 1。否则,在创建日期时,您将获得下周开始。
            【解决方案16】:

            ...是否有一个日历已经将星期一作为一周的第一天,而不是星期日。

            Someday, there will be.

            【讨论】:

              【解决方案17】:

              我这样做的简单方法是让星期一 = 0,星期日 = 6:

                  NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
                  NSInteger dayNumStartingFromMonday = ([dateComponents weekday] - 2 + 7) % 7;    //normal: Sunday is 1, Monday is 2
              

              【讨论】:

                猜你喜欢
                • 2013-02-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-07-21
                • 2020-07-17
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多