ios 如何计算核心数据中的连续天数?

baubqpgj  于 2022-11-19  发布在  iOS
关注(0)|答案(3)|浏览(127)

我需要计算最后一个连续天数,但不知道该怎么做。例如,我得到了这样的核心数据:

|id| isPresent(Bool)| date(NSDate)|
|==|================|=============|
| 1|               0| 2016-02-11  |
| 2|               1| 2016-02-11  |
| 3|               1| 2016-02-12  |
| 4|               0| 2016-02-14  |
| 5|               1| 2016-02-15  |
| 6|               1| 2016-02-16  |
| 7|               1| 2016-02-16  |

我试着检查最后一次未呈现(isPresent = 0)日期直到今天,并得到2016-02-14 -这样我就可以计算天数,这很容易。
但是,如果我将2016-02-14标记为isPresented = 1(如下表所示),我将获得最后一个未呈现日期2016-02-11 -但这是不正确的,没有2016-02-13的数据,因此该日期的isPresented应为0,连续记录应从该日期开始计数

|id| isPresent(Bool)| date(NSDate)|
|==|================|=============|
| 1|               0| 2016-02-11  |
| 2|               1| 2016-02-11  |
| 3|               1| 2016-02-12  |
| 4|               1| 2016-02-14  |
| 5|               1| 2016-02-15  |
| 6|               1| 2016-02-16  |
| 7|               1| 2016-02-16  |

我搜索了不同的算法条纹或sql reuests失踪的日期(sql server displaying missing dates),但不能想出如何使用它在核心数据。
我在想另一个数据,将保持条纹和更新,每次当用户打开应用程序,但得到同样的问题,如果用户没有打开应用程序。

**输出:**我需要找到的只是计数的天数或日期时,它打破,所以

对于第一个表:streak = 2 or breakDate = 2016-02-14 -我尝试了这个方法,但是我的解决方案错了,因为第二个表
对于第二个表:条纹= 3或中断日期= 2016-02-13 -无法确定如何获取缺失日期

**重要更新:**将有云同步数据,因此我在应用程序中看不到任何解决方案,确实需要在核心数据中找到缺失的日期或isPresented = 0
**p.s.**我正在使用swift,如果你能通过swift帮助我,那就太好了,但我也懂Obj-C。很抱歉我的英语不好

lvmkulzt

lvmkulzt1#

根据你的问题,我猜你有一个带有NSDate对象的项目实体。下面是一些代码,你可以用它来完成。

let userDefaults = NSUserDefaults.standardUserDefaults()
var moc: NSManagedObjectContext!

var lastStreakEndDate: NSDate!
var streakTotal: Int!


override func viewDidLoad() {
    super.viewDidLoad()

    // checks for object if nil creates one (used for first run)
    if userDefaults.objectForKey("lastStreakEndDate") == nil {
        userDefaults.setObject(NSDate(), forKey: "lastStreakEndDate")
    }

    lastStreakEndDate = userDefaults.objectForKey("lastStreakEndDate") as! NSDate

    streakTotal = calculateStreak(lastStreakEndDate)
}

// fetches dates since last streak
func fetchLatestDates(moc: NSManagedObjectContext, lastDate: NSDate) -> [NSDate] {
    var dates = [NSDate]()

    let fetchRequest = NSFetchRequest(entityName: "YourEntity")
    let datePredicate = NSPredicate(format: "date < %@", lastDate)

    fetchRequest.predicate = datePredicate

    do {
        let result = try moc.executeFetchRequest(fetchRequest)
        let allDates = result as! [NSDate]
        if allDates.count > 0 {
            for date in allDates {
                dates.append(date)
            }
        }
    } catch {
        fatalError()
    }
    return dates
}

// set date time to the end of the day so the user has 24hrs to add to the streak
func changeDateTime(userDate: NSDate) -> NSDate {
    let dateComponents = NSDateComponents()
    let currentCalendar = NSCalendar.currentCalendar()
    let year = Int(currentCalendar.component(NSCalendarUnit.Year, fromDate: userDate))
    let month = Int(currentCalendar.component(NSCalendarUnit.Month, fromDate: userDate))
    let day = Int(currentCalendar.component(NSCalendarUnit.Day, fromDate: userDate))

    dateComponents.year = year
    dateComponents.month = month
    dateComponents.day = day
    dateComponents.hour = 23
    dateComponents.minute = 59
    dateComponents.second = 59

    guard let returnDate = currentCalendar.dateFromComponents(dateComponents) else {
        return userDate
    }
    return returnDate
}

// adds a day to the date
func addDay(today: NSDate) -> NSDate {
    let tomorrow = NSCalendar.currentCalendar().dateByAddingUnit(.Day, value: 1, toDate: today, options: NSCalendarOptions(rawValue: 0))

    return tomorrow!
}

// this method returns the total of the streak and sets the ending date of the last streak
func calculateStreak(lastDate: NSDate) -> Int {
    let dateList = fetchLatestDates(moc, lastDate: lastDate)
    let compareDate = changeDateTime(lastDate)
    var streakDateList = [NSDate]()
    var tomorrow = addDay(compareDate)

    for date in dateList {
        changeDateTime(date)
        if date == tomorrow {
           streakDateList.append(date)
        }
        tomorrow = addDay(tomorrow)
    }

    userDefaults.setObject(streakDateList.last, forKey: "lastStreakEndDate")
    return streakDateList.count
}

我把调用放在viewDidLoad中,但是如果你愿意,你可以把它添加到一个按钮上。

jckbn6z7

jckbn6z72#

所有SQL解决方案

请注意,这是假设“今天”在计算的连续记录中计为一天。SQL会传回以天数表示的连续记录,以及连续记录开始之前的日期。

with max_zero_dt (zero_dt) as
(
  select max(dt)
    from ( 
         select max(isPresent) as isPresent, dt from check_tab group by dt
         union select 0, min(dt) from check_tab
         )
   where isPresent = 0
),
days_to_check (isPresent, dt) as
(
  select isPresent, dt
    from check_tab ct
    join max_zero_dt on ( ct.dt >= zero_dt )
),
missing_days (isPresent, dt) as
(
  select 0, date(dt, '-1 day') from days_to_check
  UNION
  select 0, date('now')
),
all_days_dups (isPresent, dt) as
(
  select isPresent, dt from days_to_check
  union
  select isPresent, dt from missing_days
),
all_days (isPresent, dt) as
(
  select max(isPresent) as isPresent, dt
  from all_days_dups
  group by dt
)
select cast(min(julianday('now') - julianday(dt)) as int) as day_streak
     , max(dt) as dt
  from all_days
 where isPresent = 0

下面是第一个场景的sqlfiddle:http://sqlfiddle.com/#!7/0f781/2
下面是第二个场景的sqlfiddle:http://sqlfiddle.com/#!7/155bb/2
关于小提琴的注意事项:他们将日期更改为相对于“今天”的日期,以便它准确地测试连胜。
下面是它的工作原理:

  • SUMMARY:我们将用零“填充”缺少的日期,然后执行简单的检查以查看最大0日期是什么时候。但是,我们必须考虑今天是否没有行,以及是否没有带零的行。
  • 最大归零日期:包含单一数据列,其中包含最新的明确0日期,或最早日期减去1天。这是为了减少稍后查询的数据列数目。
  • 检查天数:这是根据最新的0为的时间减少的要检查的行数。
  • 缺少天数(_D):我们需要填入缺失的天数,这样我们得到的是所有天数减去1天后的列表。如果没有对应的行,我们还添加了今天。
  • 所有_天_副本:我们只需将days_to_check和missing_days组合在一起。
  • all_days:这里我们得到了每一天的'max' isPresent,这样我们就得到了要搜索的真正的日期列表,知道了isPresent不会有任何0的间隔。
  • 最终质询:这是一个简单的计算,提供了连胜和开始日期。

假设:

  • 表格名称为:检查标签(_T)
  • 当前日期在表中必须为1。否则,条纹为0。如果不是这种情况,则可以修改查询。
  • 如果某一天的isPresent同时为0和1,则1优先,连续运行可以延续到前几天。
  • Core Data使用SQLite,而在SQLite中工作的上述SQL也将与Core Data的数据库一起工作。
xzv2uavs

xzv2uavs3#

import SwiftUI

extension Date {
    
    // for tomorow's Date
    static var tomorrow:  Date { return Date().dayAfter }
    static var today: Date {return Date()}
    var dayAfter: Date {
       return Calendar.current.date(byAdding: .day, value: 1, to: Date())!
        // just add .minute after byAdding: , to create a streak minute counter and check the logic.
    }

    static func getTodayDate() -> String {

           let dateFormatter = DateFormatter()

           dateFormatter.dateFormat = "E d MMM yyyy"
        //to continue with the minute streak builder just add "E d MMM yyyy h:mm a" above, it will allow date formatting with minutes and follow the changes in dayAfter

        return dateFormatter.string(from: Date.today)

       }
    
    static func getTomDate() -> String {
        let dateFormatter = DateFormatter()
        
        dateFormatter.dateFormat = "E d MMM yyyy"
        
        return dateFormatter.string(from: Date.tomorrow)
    }
}

struct StreakApp: View {
    
    @AppStorage("counter") var counter = 0
    @AppStorage("tapDate") var TapDate: String?
    @AppStorage("Tappable") var ButtonTapped = false
    var body: some View {
        NavigationView {
            VStack{
                VStack {
                    Text("\(counter)").foregroundColor(.gray)
                    Text("Restore your streak on ")
                    Text(TapDate ?? "No Date")
                    Image(systemName: "flame")
                        .resizable()
                        .frame(width: 40, height: 50)
                        .padding()
                        .scaledToFit()
                        .background(ButtonTapped ? Color.red : Color.gray)
                        .foregroundColor(ButtonTapped ? Color.orange : Color.black)
                        .cornerRadius(12)
                }
                Button {
                    if  TapDate == nil {
                        //Check if user has already tapped
                        self.ButtonTapped = true
                        counter += 1
                        self.TapDate = ("\(Date.getTomDate())")
                    }
                    else if ("\(Date.getTodayDate())") == TapDate {
                        //Check for the consecutive Day of Streak
                       
                        self.TapDate = ("\(Date.getTomDate())")
                        counter += 1
                        //Let's light the flame back again.
                        self.ButtonTapped = true
                    }
                    
                } label: {
                    RoundedRectangle(cornerRadius: 12, style: .continuous)
                        .foregroundColor(.black)
                        .frame(width: 120, height: 40)
                        .overlay {
                            Text("Add Streak")
                                .foregroundColor(.white)
                        }
                }
                .padding()
                //This button is only for testing purpose.
                Button {
                    self.TapDate = nil
                    self.ButtonTapped = false
                    self.counter = 0
                } label: {
                    RoundedRectangle(cornerRadius: 12, style: .continuous)
                        .foregroundColor(.black)
                        .frame(width: 160, height: 40)
                        .overlay {
                            Text("Reset Streak")
                                .foregroundColor(.white)
                        }
                }
          
            }
            //Ensuer the flame dies out if we run into any other day except today or tommorow.
            .onAppear {
                if ("\(Date.getTodayDate())") == TapDate ||
                    ("\(Date.getTomDate())") == TapDate {
                    self.ButtonTapped = true
                }
                //Breaking the Streak
                else {
                    self.TapDate = nil
                    self.ButtonTapped = false
                    self.counter = 0
                }
          
            }
        }
    }
}

struct StreakApp_Previews: PreviewProvider {
    static var previews: some View {
        StreakApp()
    }
}

相关问题