dapatkan NSDate hari ini, kemarin, Minggu ini, Minggu lalu, Bulan ini, Bulan lalu… variabel

86

Yang saya coba lakukan adalah mendapatkan NSDate hari ini, kemarin, Minggu ini, Minggu lalu, Bulan ini, variabel Bulan lalu siap untuk perbandingan untuk tajuk yang akan ditambahkan pada UITableView's titleForHeaderInSection

Yang saya inginkan dilakukan secara manual pada kode di bawah ini untuk tanggal 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"];
hasnat
sumber

Jawaban:

93

Diadaptasi dari Panduan Pemrograman Tanggal dan Waktu :

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

Jika Anda ingin jumlah hari yang tepat tergantung bulannya, Anda harus menggunakan file NSCalendar.

Ben S
sumber
77
Konstanta tetap untuk waktu adalah BAD BAD BAD. Bagaimana dengan hari kabisat atau detik kabisat? Gunakan NSDateComponents atau Anda AKAN mengalami beberapa masalah yang sangat buruk dan sulit untuk di-debug ketika stempel tanggal Anda mulai tidak cocok.
Kendall Helmstetter Gelner
11
Benar-benar tidak terlalu buruk jika Anda hanya menginginkan kira-kira posting minggu lalu atau apa pun. Saya menetapkan bahwa OP harus digunakan NSCalendarjika ketelitian diperlukan.
Ben S
2
Konstanta tetap seharusnya baik-baik saja untuk menghitung hari: setiap hari adalah 86400 detik. Detik kabisat hanya membutuhkan waktu dua kali lebih lama - satu hari dengan detik kabisat masih memiliki 86400 'detik'. Adapun bulan ... ya jauhi :)
Chris
3
@Ris_kecuali saat hari bukan 86400 detik. Bagaimana dengan waktu musim panas? Kedengarannya tidak penting, tetapi ini sebenarnya dapat membawa Anda ke bug super gnarly yang muncul entah dari mana ketika DST menyerang dan Anda tidak ingat untuk memperhitungkannya.
jpswain
1
Jika Anda hanya ingin kembali katakan kira-kira 7 hari, Anda bisa mengurangi waktunya, jika Anda ingin kembali ke 'Senin' minggu ini, gunakan NSCalendar. Ada kasus penggunaan untuk kedua skenario.
Johnny Rockex
83

Mungkin cara yang lebih baik untuk menulis ini tetapi inilah yang saya temukan atas saran NSCalendar Ben dan bekerja dari sana ke 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);
hasnat
sumber
13
Anda membocorkan memori dengan fromDate:[[NSDate alloc] init]potongan - potongan itu.
Shaggy Frog
21
@ Shaggy Frog: Saya kira dia berasumsi ARC diaktifkan ...;)
orj
3
Kode ini tidak bekerja dengan benar. Ini tidak memperhitungkan pecahan detik yang merupakan bagian dari tanggal input. Yaitu, tanggal bisa memiliki 30,1234 detik dan NSDateComponents hanya memiliki 30 sebagai nilai detik sehingga mengurangi 30 detik dari NSDate membuat Anda 0,1234 detik lewat tengah malam. Juga, beberapa hari memiliki lebih dari (atau kurang) dari 24 jam (penghematan siang hari) sehingga mendapatkan tanggal kemarin harus benar-benar menggunakan [komponen setDay: -1] daripada [komponen setHour: -24].
orj
5
@orj FYI, ARC keluar lama setelah jawaban itu diposting
Shaggy Frog
3
@orj Selain itu, pada perubahan waktu musim panas, mengurangi jam tidak memberi Anda tengah malam. -1. Kode ini tidak sebanding dengan 35 suara positif.
Nikolai Ruhe
40

NSDateComponents bagus untuk didapatkan hari ini:

NSCalendar *cal = [NSCalendar currentCalendar];

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

Ini membuat NSDate hanya dengan tahun, bulan dan tanggal:

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

Untuk mendapatkan kemarin, dll. Anda dapat menghitungnya menggunakan NSDateComponents:

NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:-1];
NSDate *yesterday = [cal dateByAddingComponents:components toDate:today options:0];
Bir Kristen
sumber
Apakah Anda tidak perlu memasukkan komponen era?
Chris Halaman
Bagus. Digunakan untuk menghitung tanggal 8 tahun yang lalu dan berfungsi dengan baik. Hanya perlu memperbaiki kebocoran di sini: [[NSDateComponents alokasi] init];
Craig B
@Raigm Ini tidak dimaksudkan sebagai contoh yang lengkap. Meninggalkan manajemen memori yang jelas sebagai tantangan bagi pembaca;)
Christian Beer
@ ChrisPage komponen era? Untuk apa?
Bir Kristen
1
@ChristianBeer Saya cukup yakin semua komponen yang lebih besar dari resolusi yang diinginkan harus dipertimbangkan. Saya percaya (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)seharusnya (NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit).
Chris Halaman
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];
}
Dustin
sumber
Apakah Anda tidak perlu memasukkan komponen era?
Chris Halaman
Saya harus menghapus NSDayCalendarUnit dan menambahkan NSWeekdayCalendarUnit saat menghitung DateLastWeek.
jessecurry
Apple mengubah definisi NSWeekdayCalendarUnit dan NSDayCalendarUnit di sekitar iOS 5.0. Cara baru adalah menggunakan NSWeekdayCalendarUnit. Tetapi pada versi yang lebih lama Anda harus menggunakan NSDayCalendarUnit. Ini berantakan ...
Dustin
@Dustin Sepertinya tidak berfungsi, bahkan saat memperbarui ke unit baru ... Misalnya DateThisWeek, menyetel hari kerja tidak berdampak pada NSDate ...
AnthoPak
12

Swift 4.2.0

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)

Harap dicatat bahwa komponen tanggal adalah opsional.

gokhanakkurt.dll
sumber
1
@fengd well, Hari ini 27 Jun 2016, jam 1 pagi tanggal 28 Jun 2016, dan jika saya kurangi 24 jam, tanggal 27 Jun 1 pagi. Apa poin yang saya lewatkan?
gokhanakkurt
1
maaf, @gokhanakkurt. Saya pikir ada beberapa masalah dalam pikiran saya. jawaban Anda benar
fengd
4

Jawaban lain tidak berhasil untuk saya (mungkin karena zona waktu saya). Inilah cara saya melakukannya:

- (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;
}
Lucas
sumber
4

Jika Anda menggunakan iOS 10+ atau MacOS 10.12+, Anda dapat menggunakan dua Calendarmetode ini untuk melakukannya dengan benar.

  • func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool = default) -> Date?( dokumen )
  • func dateInterval(of component: Calendar.Component, for date: Date) -> DateInterval?( dokumen )

Berikut adalah contoh cara menggunakan metode ini di Swift 3, bersama dengan output taman bermain di zona waktu saya.

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

Bonus: Anda dapat menggunakan DateIntervals untuk menguji apakah tanggal termasuk dalam kisaran itu. Melanjutkan dari atas:

thisWeekInterval!.contains(now)
// => true
lastMonthInterval!.contains(now)
// => false
yood
sumber
Mengapa yesterdaydikatakan 29 Apr dan now28 Apr?
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];
hayden
sumber
0

Saya sangat menyukai objek THCalendarInfo yang terdapat dalam proyek ini:

http://github.com/jaredholdcroft/kcalendar

Saya tidak dapat menemukan yang asli. Dengan menggunakan objek ini, Anda dapat pindah ke hari sebelumnya, awal minggu, awal bulan, mendapatkan hari dalam seminggu, hari dalam sebulan ... dll.

Kendall Helmstetter Gelner
sumber
0
NSDate *today = [[NSDate alloc] initWithTimeIntervalSinceNow:0];
Tischel
sumber
Karena keduanya valid untuk mendapatkan tanggal sekarang, maka keduanya menyertakan waktu. Jadi, ini bukan solusi yang tepat untuk pertanyaan itu!
Bir Kristen
0

Ini untuk mengecek tanggalnya bulan ini atau tidak

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
}

Dan yang kedua hanya mengubah jenis calendarUnit yang lemah seperti ini

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
}

Saya harap ini membantu seseorang. Terima kasih.

Ilesh P.
sumber
0

Aku menjawab pertanyaan serupa sudah dan inilah mengapa jawaban saya adalah lebih baik:

  • Cepat 3 !
  • Memanfaatkan "Yesterday" dan "Today" dari DateFormatter. Ini sudah diterjemahkan oleh Apple, yang menghemat pekerjaan Anda!
  • Menggunakan string "1 minggu" DateComponentsFormatter yang sudah diterjemahkan. (Sekali lagi lebih sedikit pekerjaan untuk Anda, milik Apple.) Yang harus Anda lakukan adalah menerjemahkan string "% @ lalu". 🙂
  • Jawaban lain salah menghitung waktu ketika hari beralih dari "hari ini" ke "kemarin" ke dll. Konstanta tetap adalah TIDAK-TIDAK besar karena alasan . Juga, jawaban lain menggunakan tanggal / waktu saat ini ketika mereka harus menggunakan akhir dari tanggal / waktu hari ini .
  • Menggunakan autoupdatingCurrent untuk Kalender & Lokal yang memastikan aplikasi Anda segera diperbarui dengan kalender pengguna dan preferensi bahasa di Settings.app
ChrisJF
sumber