2014-09-01 120 views
0

我正在做一個簡單的班次跟蹤器/薪水計算器來練習CoreData和Swift。我在與此相關的不同任務的問題,因爲我需要使用日期:CoreData存儲日期推薦做法

  • 顯示他們
  • 轉變的檢查量在一週內看到,如果你應得加班工資(挪威規則給你5/10 $ +每小時額外的,如果你在一個月的工作,每週不超過12小時)
  • 將所有工資一起
  • 刪除的數據,如果在錯誤的

,可能更多的用戶類型我忘了。

從現在開始,我從日期選擇器獲取數據,它使用日期格式化程序將它們作爲字符串從「fromDate」和「toDate」添加到DB中。這導致我不得不使用一堆不好的代碼。很大程度上是因爲NSDate時區問題等。

我應該如何佈置我的數據庫來最有效地做到這一點?我應該爲每種類型的數據創建一個字段嗎? ('fromMinute'|'fromHour'|'fromDay'|'fromWeek'|'fromMonth'|'fromYear'),然後對應'to'字段?我是數據庫的新手,但我認爲我不應該擁有那麼多的領域。我應該有一個月表,然後是一個星期表,然後使用關係(在那種情況下,我該怎麼做?)

我不能只使用一個時間間隔,因爲獎金取決於它有多晚。

希望有人能幫助我與一些推薦的做法在CoreData


UPDATE:

這裏是我的超級複雜的核心數據模型! enter image description here

用NSManagedObject類(我認爲)沿

import UIKit 
import CoreData 

@objc(Shifts) 

class Shifts: NSManagedObject { 
    @NSManaged var fromDate : String 
    @NSManaged var toDate : String 

    func getShift() -> Shift{ 
     let formatter = NSDateFormatter() 
     formatter.dateFormat = "yyyy-MM-dd w W HH:mm" 
     let from:NSDate = formatter.dateFromString(self.fromDate)! 
     let to:NSDate = formatter.dateFromString(self.toDate)! 
     let length:Double = to.timeIntervalSinceDate(from) as Double/60 

     let newShift = Shift(from:from,to:to,length:length) 
     return newShift 
    } 


} 

媽是一類我在我的視圖控制器,我用它來顯示等我的數據,它看起來像這樣(TW:代碼戈爾)

class Shift { 
var fromDate : NSDate 
var toDate : NSDate 
var length : Double //In Minutes 
var salary : Double = Double() 
var UB : Bool = false 

let etter18hverdag:Double = 22 
let etter21hverdag:Double = 45 
let helligdag:Double = 90 
let helgEtter13:Double = 45 
let helgEtter16:Double = 90 //HUSK AT PAUSE FINNES 


init (from : NSDate, to : NSDate, length:Double){ 
    self.fromDate = from 
    self.toDate = to 
    self.length = length 
} 
func calcSalary(ub: Bool)->Double{ 

    let userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults() 
    let hour: Double = userDefaults.doubleForKey("salary") 

    println("Checking salary on shift fromDate:\(fromDate) with length:\(length). Shift UB: \(UB)") 

    if (ub){ 
     let calendar : NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar) 
     calendar.locale = NSLocale.systemLocale() 
     calendar.timeZone = NSTimeZone.localTimeZone() 

     var checkTime:NSDate = fromDate 
     var checkToTime:NSDate = toDate 

     var totalSalary:Double = Double() 

     while (checkToTime.timeIntervalSinceDate(checkTime)>0.0){ 

      let split = calendar.components(NSCalendarUnit.WeekdayCalendarUnit | NSCalendarUnit.HourCalendarUnit, fromDate: checkTime) 

      println("Checking: \(checkTime) to: \(checkToTime) diff:\(checkToTime.timeIntervalSinceDate(checkTime)) currentSal: \(totalSalary) splitTime:\(split.hour)") 
      if(split.weekday==7){ //Søndag 
       let lønn = hour + helligdag 
       totalSalary += (lønn/4) 
      } 

      else if (split.weekday == 6){ //Lørdag 
       if(split.hour < 13){ 
        let lønn = hour 
        totalSalary += (lønn/4) 
       } 
       if (split.hour>13 && split.hour<16){ 
        let lønn = hour + helgEtter13 
        totalSalary += (lønn/4) 

       } 
       if (split.hour > 16){ 
        let lønn = hour + helgEtter16 
        totalSalary += (lønn/4) 
       } 

      } 

      else if (split.weekday < 6){ //Hverdag 
       if(split.hour < 18){ 
        let lønn = hour 
        totalSalary += (lønn/4) 

       } 
       if (split.hour>18 && split.hour<21){ 
        let lønn = hour + etter18hverdag 
        totalSalary += (lønn/4) 

       } 
       if (split.hour > 21){ 
        let lønn = hour + etter21hverdag 
        totalSalary += (lønn/4) 
       } 
      } 


      checkTime = checkTime.dateByAddingTimeInterval(15*60) //15 min ganger 60 sek i min 
     } 
     println("Calculated salary WITH UB: \(totalSalary)") 

     return totalSalary 
    } else { 
     let calendar : NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar) 
     calendar.locale = NSLocale.systemLocale() 
     calendar.timeZone = NSTimeZone.localTimeZone() 

     var checkTime:NSDate = fromDate 
     var totalSalary:Double = Double() 
     let multiple = (length/60) 

     while (self.toDate.timeIntervalSinceDate(checkTime)>0.0){ 

      let lønn = hour 
      totalSalary += (lønn/4) 

      checkTime = checkTime.dateByAddingTimeInterval(15*60) //15 min ganger 60 sek i min 
     } 
     println("Calculated salary WITHOUT UB: \(totalSalary)") 
     return totalSalary 
    } 
} 
+0

爲什麼不使用unix時間戳?易於存儲,易於計算。 – Apfelsaft 2014-09-01 12:31:00

+0

@Oscar Apeland:你的問題對我來說還不夠清楚。我甚至不知道你的核心數據模型是什麼樣子。你是什​​麼實體,它們的屬性和關係是什麼?他們將幫助我們瞭解您對NSDate屬性的需求...... – 2014-09-01 17:21:35

+0

@POB我更新了一下我的問題,看看。而且,據我所見,它不可能將NSData存儲在coredata中? – 2014-09-02 12:04:15

回答

11

短版

最好的做法是存儲fromDatetoDateNSDate秒。

長版

什麼是約會?

一種NSDate實際上是一個NSTimeInterval是因爲參考日期。 NSTimeInterval值表示自該日期以來的秒數,並且不考慮時區,日曆或任何其他地理或政治構造。從概念上講,這與unix時間戳相同,儘管unix時間戳使用不同的參考日期(相當於timeIntervalSince1970)。 NSDate表示一個時間點 - 天,年,時區和夏令時全都是演示級別的擔憂,而NSDate只是一個值對象。這是日期表示的蜜獾。它不關心。

這就是說,顯示NSDate涉及許多其他組件,最具有本地化做的。用戶的本地化設置決定使用哪個日曆表示(NSCalendar),以及如何以可視方式格式化日期(NSDateFormatter)。用戶甚至可以在應用程序運行時更改這些設置,這就是爲什麼有一些系統通知會通知應用程序已發生變化。

使用NSCalendar進行日期計算並不難,一旦您理解了上述概念,並且去年NSCalendar被擴展爲更易於使用(不幸的是,這些改進僅在最近才發佈到iOS)。蘋果有一個很好的日曆計算指南,其中Date and Time Programming Guide: Performing Calendar Calculations和去年的WWDC WWDC 2013: Solutions to Common Date and Time Challenges的一個會話詳細介紹了對NSCalendar的改進,並且涵蓋了一些處理日期的非常好的技巧。

如果您的數據模型店爲NSDate日期這是很容易適應日期值的視覺呈現正確的用戶的本地化設置。該模型不需要知道時區,日曆和本地化設置 - 這些最好在演示文稿(視圖或視圖控制器)級別處理。

如果您將日期存儲爲字符串,日期組件或日曆組件,則會遇到很多問題。例如,如果當前日曆發生更改,則所有持久數據都將無效並需要重建。夏令時也可能是一個大問題。

這是如何影響核心數據的?

在您的情況下,您代表模型中的日期範圍(從fromDatetoDate的秒數範圍)。有表示相同的事情的一些替代方法,比如使用fromDateduration指示從fromDate一個NSTimeInterval到每當換檔結束。這兩種方法都有效。

在某個特定時段查詢數據,首先你會進行必要的calendary計算才能獲得用戶的當前區域小時的開始和結束。

例如,在Objective-C,採用新方法NSCalendar

NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; 
NSDate  *startOfDay = [calendar startOfDayForDate:fromDate]; 
NSDate  *startOfHour= [calendar dateByAddingUnit:kCFCalendarUnitHour value:8 options:NSCalendarMatchStrictly]; 
NSDate  *endOfHour = [calendar dateByAddingUnit:kCFCalendarUnitHour value:9 options:NSCalendarMatchStrictly]; 

這將使你的一天8小時的開始和結束上fromDate瀑布。這只是一個例子,您的業務規則可能會規定更多的邏輯,例如根據fromDate檢查toDate的值等 - 儘管可以通過自定義Core Data validation來處理許多這些問題。

謂詞中使用,這是一組簡單的數字比較:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.fromDate <= %@ AND SELF.fromDate >= %@", endOfHour, startOfHour]; 

當使用NSFetchedResultsController顯示部分,該sectionNameKeyPath可以指向一個核心數據瞬態特性,讓您可以根據顯示部分小時,月份等,只要你喜歡。對查詢結果進行排序和分組不能使用瞬態屬性,只能使用建模屬性支持的屬性 - 在您的案例中,fromDatetoDate。由於日期是數字並且代表時間點,所以這對於許多業務規則來說很容易工作。

+0

謝謝你這個偉大的答案,我認爲它回答了我所有的問題。 – 2014-09-08 11:04:00

+1

好的和非常全面的答案+1! – BootMaker 2015-01-17 16:05:06

0

我會建議你存儲你的日期,如日期對象。日期對象包含您需要檢索日期片段的所有數據。 然後,您可以使用類別擴展核心數據對象以檢索其片段。添加一些方法,如 - (NSInteger)年, - (NSInteger)月。 有關如何獲取日期片段,請參閱NSCalendar和NSDateComponents。它還可以幫助您添加和執行日期操作。