迭代日期数组的函数会产生意外的结果

保罗·杜迈斯

我有一个从iOS应用程序调用的CloudCode函数。该函数应该创建“签到”记录并返回一个字符串,以表示签到的最后30天和错过的日期。

奇怪的是,有时候我得到了预期的结果,有时却没有。它使我认为我可能使用的时区存在一些问题-因为这可能导致一组不同的“过去的日子”,具体取决于我运行此功能的时间以及一天中的什么时间签入过去。但我感到困惑,可以在这里使用一些帮助。

我也看不到所有console.log()结果都出现在解析日志中,这也使我感到困惑。那正常吗?例如,在for循环中,我可以取消注释console.log条目并调用该函数,但看不到过去列出的所有日期-但它们包含在最终数组和文本字符串中。

这是我的完整功能。任何帮助和建议,表示赞赏。

/* Function for recording a daily check in
 *
 * Calculates the number of days missed and updates the string used to display the check-in pattern.
 * If no days missed then we increment the current count
 *
 * Input:
 * "promiseId" : objectID,
 * "timeZoneDifference" : String +07:00
 *
 * Output:
 * JSON String  eg. {"count":6,"string":"000000000000001111101010111111"}
 *
 */
Parse.Cloud.define("dailyCheckIn", function(request, response) {
    var promiseId = request.params.promiseId;
    var timeZoneDifference = request.params.timeZoneDifference;    
    var currentUser = Parse.User.current();

    if (currentUser === undefined) {
        response.error("You must be logged in.");
    }

    if (timeZoneDifference === undefined || timeZoneDifference === "") {
        //console.log("timeZoneDifference missing. Set to -07:00");
        timeZoneDifference = '' + '-07:00'; // PacificTime as string
    }

    var moment = require('cloud/libs/moment.js');

    // Query for the Promise
    var Promise = Parse.Object.extend("Promise");
    var queryforPromise = new Parse.Query(Promise);

    queryforPromise.get(promiseId, {
        success: function(promis) {

            // Initialize
            var dinarowString = "";
            var dinarowCount = 0;

            // Last Check In date from database (UTC)
            var lastCheckInUTC = promis.get("lastCheckIn");
            if (lastCheckInUTC === undefined) {
                lastCheckInUTC = new Date(2015, 1, 1);
            }

            // Use moment() to convert lastCheckInUTC to local timezone
            var lastCheckInLocalized = moment(lastCheckInUTC.toString()).utcOffset(timeZoneDifference);
                //console.log('lastCheckIn: ' + lastCheckInUTC.toString());
                //console.log('lastCheckInLocalized: ' + lastCheckInLocalized.format());

            // Use moment() to get "now" in UTC timezone
            var today = moment().utc(); // new Date(); 
                //console.log('today: ' + today.format());

            // Use moment() to get "now" in local timezone
            var todayLocalized = today.utcOffset(timeZoneDifference);
                //console.log('todayLocalized: ' + todayLocalized.format());

            // 30 days in the past
            var thirtydaysago = moment().utc().subtract(30, 'days');
                //console.log("thirtydaysago = " + thirtydaysago.format());

            // 30 days in the past in local timezone
            var thirtydaysagoLocalized = thirtydaysago.utcOffset(timeZoneDifference);
                //console.log('thirtydaysagoLocalized: ' + thirtydaysagoLocalized.format());

            // Calculate the number of days since last time user checked in
            var dayssincelastcheckin = todayLocalized.diff(lastCheckInLocalized, 'days');
                //console.log("Last check-in was " + dayssincelastcheckin + " days ago");

            // Function takes an array of Parse.Objects of type Checkin
            // itterate over the array to get a an array of days in the past as numnber
            // generate a string of 1 and 0 for the past 30 days where 1 is a day user checked in
            function dinarowStringFromCheckins(checkins) {
                var days_array = [];
                var dinarowstring = "";

                // Create an array entry for every day that we checked in (daysago)
                for (var i = 0; i < checkins.length; i++) {
                    var checkinDaylocalized = moment(checkins[i].get("checkInDate")).utcOffset(timeZoneDifference);
                    var daysago = todayLocalized.diff(checkinDaylocalized, 'days');
                    // console.log("daysago = " + daysago);
                    days_array.push(daysago);
                }
                console.log("days_array = " + days_array);

                // Build the string with 30 day of hits "1" and misses "0" with today on the right
                for (var c = 29; c >= 0; c--) {
                    if (days_array.indexOf(c) != -1) {
                        //console.log("days ago (c) = " + c + "-> match found");
                        dinarowstring += "1";
                    } else {
                        dinarowstring += "0";
                    }
                }
                return dinarowstring;
            }

            // Define ACL for new Checkin object
            var checkinACL = new Parse.ACL();
            checkinACL.setPublicReadAccess(false);
            checkinACL.setReadAccess(currentUser, true);
            checkinACL.setWriteAccess(currentUser, true);

            // Create a new entry in the Checkin table
            var Checkin = Parse.Object.extend("Checkin");
            var checkin = new Checkin();
            checkin.set("User", currentUser);
            checkin.set("refPromise", promis);
            checkin.set("checkInDate", today.toDate());
            checkin.setACL(checkinACL);
            checkin.save().then(function() {
                // Query Checkins
                var Checkin = Parse.Object.extend("Checkin");
                var queryforCheckin = new Parse.Query(Checkin);
                queryforCheckin.equalTo("refPromise", promis);
                queryforCheckin.greaterThanOrEqualTo("checkInDate", thirtydaysago.toDate());
                queryforCheckin.descending("checkInDate");
                queryforCheckin.find().then(function(results) {
                    var dinarowString = "000000000000000000000000000000";
                    var dinarowCount = 0;
                    if (results.length > 0) {
                        dinarowString = dinarowStringFromCheckins(results);
                        dinarowIndex = dinarowString.lastIndexOf("0");
                        if (dinarowIndex === -1) { // Checked in every day in the month!
                            // TODO
                            // If the user has checked in every day this month then we need to calculate the 
                            // correct streak count in a different way 
                            dinarowString = "111111111111111111111111111111";
                            dinarowCount = 999;
                        } else {
                            dinarowCount = 29 - dinarowIndex;
                        }
                    }
                    // Update the promise with new value and save
                    promis.set("dinarowString", dinarowString);
                    promis.set("dinarowCount", dinarowCount);
                    promis.set("lastCheckIn", today.toDate());
                    promis.save().then(function() {
                        response.success(JSON.stringify({
                            count: dinarowCount,
                            string: dinarowString
                        }));
                    });
                }, function(reason) {
                    console.log("Checkin query unsuccessful:" + reason.code + " " + reason.message);
                    response.error("Something went wrong");
                });

            }); // save.then
        },
        error: function(object, error) {
            console.error("dailyCheckIn failed: " + error);
            response.error("Unable to check-in. Try again later.");
        }
    });
});
保罗·杜迈斯

找到解决方案后,我正在回答自己的问题。

我有两个问题。第一个是“为什么我会得到意外的(不正确的)结果”,我怀疑这与我使用时区的方式有关。我每天会看到不同的结果,具体取决于我检查的时间。

问题实际上与moment()。diff()的工作方式有关。Diff并不像我期望的那样计算“天数”。如果我今天凌晨2点与昨天晚上11点进行比较,差异将表示0天,因为它少于24小时差异。如果我将周四凌晨1点与上一个周一的晚上8点进行比较,差异将报告2天,而不是我预期的3天。这是一个精度问题。Diff认为2.4天是2天前。但是它是3天前的2个以上。

我们发现,最简单的解决方案是比较午夜的两个日期,而不是数据库中记录的实际时间。这几天会产生正确的结果。其余代码工作正常。

            //Find start time of today's day
            var todayLocalizedStart = todayLocalized.startOf('day');

            for (var i = 0; i < checkins.length; i++) {
                var checkinDaylocalized = moment(checkins[i].get("checkInDate")).utcOffset(timeZoneDifference);

                //Find start time of checkIn day
                var checkinDaylocalizedStart = checkinDaylocalized.startOf('day');

                //Find number of days
                var daysago = todayLocalizedStart.diff(checkinDaylocalizedStart, 'days');
                // console.log("daysago = " + daysago);

                days_array.push(daysago);
            }

我遇到的第二个问题是“在运行时看不到每个console.log是否正常”。我已经与其他Parse.com用户进行了交谈,他们报告说Parse与日志记录不一致。我花了很多时间来调试“问题”,而这些问题只是Parse无法正确记录。

感谢所有为答案做出贡献的人。

我确实做了另一个更改-但这不是一个错误。我将查询限制从过去的30天替换为简单的“ 30”。只需较少的计算就可以简单一点。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章