CoreData用于存储日期推荐的做法

时间:2014-09-01 11:39:14

标签: ios sql sqlite core-data swift

我正在制作一个简单的移位跟踪器/工资计算器来练习CoreData和Swift。我遇到与此相关的不同任务的问题,因为我需要使用日期:

  • 显示它们
  • 检查一周内的轮班金额,看看你是否应该支付额外的工资(如果你每周工作超过12小时,挪威规则每小时可以获得5/10美元+额外费用)
  • 一起加入所有薪水
  • 如果用户键入错误的
  • ,则删除数据

我可能会忘记更多。

截至目前,我正在从日期选择器获取数据,这些日期选择器使用日期格式器将数据库添加到数据库中,以及来自日期的数据。和'日期'作为一个字符串。这导致我不得不使用一堆坏代码。很多是因为NSDate时区问题等。

我应该如何布置我的数据库以最有效地完成此操作?我应该为我需要的每种类型的数据创建一个字段吗? (' fromMinute' |' fromHour' |' fromDay' |' fromWeek' |' fromMonth' |' fromYear')然后对应'到'字段?我是数据库的新手,但我不认为我应该拥有那么多领域。我应该有月表,然后是周表,然后使用关系(在这种情况下我该怎么做?)

我不能只使用时间间隔,因为奖金取决于它有多晚。

希望有人可以帮我解决一些关于CoreData的推荐做法


更新:

这是我超级复杂的核心数据模型! 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
    }


}

Shit是我在视图控制器中的一个类,我用它来显示我的数据,它看起来像这样(TW:Code Gore)

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

2 个答案:

答案 0 :(得分:13)

短版

最佳做法是将fromDatetoDate存储为NSDate

长版

约会对象是什么?

自参考日期起,NSDate实际上是NSTimeIntervalNSTimeInterval值表示自该日期以来的秒数,无论时区,日历或任何其他地理或政治结构如何。从概念上讲,这与unix时间戳相同,但unix时间戳使用不同的引用日期(相当于timeIntervalSince1970)。 NSDate表示一个时间点 - 天,年,时区和夏令时都是表示级别关注点,而NSDate只是一个值对象。它是日期陈述的蜜獾。它不在乎。

也就是说,显示NSDate涉及许多其他组件,大多数都与本地化有关。用户的本地化设置确定使用哪个日历表示(NSCalendar),以及如何以可视方式格式化日期(NSDateFormatter)。用户甚至可以在应用程序运行时更改这些设置,这就是为什么有一些系统通知可以通知您的应用程序存在更改。

使用NSCalendar执行日期计算并不是很难理解上述概念,并且去年NSCalendar扩展到更容易使用(不幸的是,这些改进仅在iOS上出现了最近)。 Apple在Date and Time Programming Guide: Performing Calendar Calculations中有一个很好的日历计算指南,而去年WWDC的会话WWDC 2013: Solutions to Common Date and Time Challenges详细介绍了对NSCalendar的改进,并提供了一些非常好的提示一般情况下使用日期。

如果您的数据模型将日期存储为NSDate,则可以更轻松地为用户的本地化设置正确调整日期值的可视化表示。该模型不需要了解时区,日历和本地化设置 - 最好在演示(视图或视图控制器)级别处理。

如果您将日期存储为字符串,日期组件或日历组件,则会遇到很多问题。例如,如果当前日历已更改,则所有持久数据都将无效,需要重建。夏令时也可能是个大问题。

这对核心数据有何影响?

在您的情况下,您要在模型中表示日期范围(从fromDatetoDate的秒数范围)。有一些代表同一事物的替代方法,例如使用fromDateduration表示NSTimeInterval fromDate到班次结束时。这两种方法都有效。

在查询特定小时的数据时,首先要执行必要的日历计算,以便在用户的当前区域设置中获取小时的开始和结束时间。

例如,在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];

这将为您提供fromDate落下的当天第8小时的开始和结束。这只是一个示例,您的业务规则可能会规定更多逻辑,例如检查toDate对fromDate的值等等 - 尽管通过自定义Core Data validation可以最好地处理其中的许多问题。

在谓词中使用它是一组简单的数字比较:

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

使用NSFetchedResultsController显示部分时,sectionNameKeyPath可以指向核心数据瞬态属性,以允许您根据需要显示基于小时,月份等的部分。对查询结果进行排序和分组不能使用瞬态属性,只能使用由建模属性支持的属性 - 在您的情况下,fromDatetoDate。由于日期是数字并代表一个时间点,因此很容易适用于许多业务规则。

答案 1 :(得分:0)

我建议您将日期存储为日期对象。日期对象包含检索日期片段所需的所有数据。 然后,您可以使用类别扩展核心数据对象以检索其片段。添加一些方法,如 - (NSInteger)年, - (NSInteger)月。 有关如何获取日期片段的信息,请参阅NSCalendar和NSDateComponents。它还可以帮助您在日期添加和执行操作。