오늘, 어제, 이번 주, 지난주, 이번 달, 지난달… 변수


86

나는 오늘, 어제, 이번 주, 지난주, 이번 달, 지난달 변수를 UITableView의 titleForHeaderInSection에 추가 할 헤더에 대한 비교 준비를 위해 NSDate를 얻으려고합니다.

내가 원하는 것은 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 2009

11
지난주에 게시 한 게시물이나 그 밖의 것을 원하는 경우에는 그렇게 나쁘지 않습니다. NSCalendar정확성이 필요한 경우 OP가 사용해야한다고 지정했습니다 .
Ben S

2
고정 상수는 실제로 날짜 계산에 적합해야합니다. 매일 86400 초입니다. 윤초는 단순히 두 배의 시간이 소요됩니다. 윤초가있는 하루에도 여전히 86400 초가 있습니다. 달에 관해서는 ... 그래 분명 조종 :)
Chris

3
@Chris는 일이 86400 초가 아닌 경우를 제외하고. 일광 절약 시간은 어떻습니까? 사소하게 들리지만 실제로 DST가 맞았을 때 갑자기 나타나는 아주 형편없는 버그로 이어질 수 있고 그것을 고려하는 것을 기억하지 못했습니다.
jpswain 2013 년

1
대략 7 일 정도 돌아가고 싶다면 시간을 빼면됩니다. 이번주의 '월요일'로 돌아가려면 NSCalendar를 사용하세요. 두 시나리오 모두에 대한 사용 사례가 있습니다.
Johnny Rockex

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]비트들로 온통 메모리를 누출하고 있습니다.
Shaggy Frog

21
@Shaggy Frog : ARC가 활성화되어 있다고 가정하고있는 것 같습니다 ...;)
orj

3
이 코드는 제대로 작동하지 않습니다. 입력 날짜의 일부인 초의 일부는 고려하지 않습니다. 즉, 날짜는 30.1234 초를 가질 수 있고 NSDateComponents는 초 값으로 30 만 가질 수 있으므로 NSDate에서 30 초를 빼면 자정 이후 0.1234 초가 남습니다. 또한 어떤 날은 24 시간 (일광 절약)보다 많거나 적으므로 어제의 날짜를 얻으려면 실제로 [components setHour : -24]가 아닌 [components setDay : -1]을 사용해야합니다.
ORJ

5
그 대답을 게시 한 후 참고 @orj, ARC는 나이를 나왔다
얽히고 설킨 개구리

3
@orj 또한 일광 절약 시간이 변경 될 때 시간을 빼도 자정이 제공되지 않습니다. -1. 이 코드는 35 개 찬성 할 가치가 없습니다.
Nikolai Ruhe 2013 년

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

Apple은 iOS 5.0에서 NSWeekdayCalendarUnit 및 NSDayCalendarUnit의 정의를 변경했습니다. 새로운 방법은 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 잘, 오늘 2016 년 6 월 27 일 오전 1시 날짜는 2016 년 6 월 28 일이며 24 시간을 빼면 날짜는 6 월 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에서 이러한 메서드를 사용하는 방법과 제 시간대의 놀이터 출력에 대한 예입니다.

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

yesterday4 월 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
}

그리고 두 번째는 이렇게 약한 경우 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"문자열 만 번역하면됩니다. 🙂
  • 다른 답변은 하루가 "오늘"에서 "어제"로 전환되는 시간을 잘못 계산합니다 . 이유 때문에 고정 상수는 큰 NO-NO 입니다. 또한 다른 답변은 현재 날짜 / 시간의 끝을 사용해야 할 때 현재 날짜 / 시간을 사용합니다 .
  • 캘린더 및 로케일에 대해 autoupdatingCurrent를 사용하여 앱이 Settings.app의 사용자 캘린더 및 언어 기본 설정으로 즉시 업데이트되도록합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.