如何让 Bootstrap DateTimePicker 显示正确的年份?

How do I get the Bootstrap DateTimePicker to display the correct year?

我维护的网站的功能之一是 creating/updating 即将举行的活动。用户需要能够 select 事件的日期和时间,但我发现如果日期 selected 是在一年的最后一周内,并且该周有几天是在下一年,那么年份自动设置为下一年。

例如,如果 selected 为 2019 年 12 月 29 日,则插入数据库的日期为 2020 年 12 月 29 日。 此外,如果我打开一个包含事件数据的模块,它将显示日期为 2021 年 12 月 29 日,即使数据库将其记录为 2020 年。

由于 2019 年 12 月 28 日是星期六,与 2020 年的日子不在同一周,因此将其作为 2019 年 12 月 28 日插入数据库。

下面是事件模块的一些 ColdFusion 代码:

<div class="form-group">
    <cfdump var="#event.event_date_time#" expand="yes"></cfdump>
    <label>Event Date and Time:</label>
    <div class='input-group date' id='updateEventDateTime'>
        <input required type='text' name="updateEventDateTime" class="form-control" 
               placeholder="Select event date and time" 
               value="#DateTimeFormat(event.event_date_time,'MM/dd/YYYY H:nn tt')#"/>
        <span class="input-group-addon">
            <span class="glyphicon glyphicon-calendar"></span>
        </span>
    </div>
    <cfdump var="#event.event_date_time#" expand="yes"></cfdump>
</div>

这是 DateTimePicker 的 javascript:

<script>
    $(document).ready(function(e) {

        // Create the Bootstrap Datetimepicker for the event
        // date and time
        $('#updateEventDateTime').datetimepicker({
            format: 'MM/DD/YYYY H:mm A',
            sideBySide: true
        });

    });
</script>

以下是上述 ColdFusion 代码输出的屏幕截图:

日期时间错误的年份:

有什么办法可以解决这个问题吗?在过去的 2 年里,我一直在维护这个网站,这不是问题,虽然现在对用户来说显然不是问题,但它会在 November/December 中,我宁愿现在就修复它.

编辑:有两个主要操作都需要修复。用户需要能够添加事件和更新事件。上面的ColdFusion代码在updateEvent模块中,addEvent模块的部分代码如下:

<div class="form-group">
    <label>Event Date and Time:</label>
    <div class='input-group date' id='addEventDateTime'>
        <input required type='text' name="addEventDateTime" class="form-control" 
               placeholder="Select event date and time" />
        <span class="input-group-addon">
            <span class="glyphicon glyphicon-calendar"></span>
        </span>
    </div>
</div>

此模块中的 javascript 代码包含:

<script>
$(document).ready(function(e) {

    // Create the Bootstrap Datetimepicker for the event
    // date and time
    $('#addEventDateTime').datetimepicker({
        format: 'MM/DD/YYYY H:mm A',
        sideBySide: true
    });

我解决了我的问题。当按下 "Save" 按钮时,数据被放入一个传递给以下函数的结构中:

<cffunction name="addEvent" access="public" returntype="any">
<cfargument name="eventStruct" type="struct" required="yes">
<!--- Verify the structure is formated correctly --->

<!--- Checks if all the required elements of the struct are there --->

<!--- Verify the date object is correct --->
<cfif NOT isDate(ARGUMENTS.eventStruct.eventDateTime)>
    <cfset errorCode = "INVALID_VARIABLE_TYPE">
    <cflog file="chapter-reports" type="error" 
        text="#errorCode#: variable must be a coldfusion date object">
    <cfreturn errorCode />
</cfif>
<!--- Format the date --->
<cfset ARGUMENTS.eventStruct.eventDateTime = DateTimeFormat(ARGUMENTS.eventStruct.eventDateTime,"yyyy-MM-dd HH:nn:ss")>
<!--- Insert the event into the table --->
<cftry>
    <cfquery datasource="#VARIABLES.datasource#" name="insertEvent" result="newEvent">
        INSERT INTO #VARIABLES.tablePrefix#events
        (/*column names*/,event_date_time,/*more column names*/)
        VALUES(
            /*data*/,
            '#ARGUMENTS.eventStruct.eventDateTime#',
            /*more data*/
        )
    </cfquery>

    <!--- Send an error message if there is a database error --->

</cftry>
<cfreturn newEvent.generated_key />

最初,它会将日期格式化为 "YYYY",但在将其更改为 "yyyy" 后,它会按预期工作。

您在这里谈论的是多种不同的事情:您正在使用 Bootstrap 模板中的 Java 脚本、ColdFusion 变量和数据库。所有 3 个都会影响您看到的最终日期,并且您看到的不是日期对象(就像数据库最终应该想要的那样),而是日期对象的字符串表示形式。

当您查看日期时,它可能看起来像 March 27, 2019 12:00:00 pm03/27/2019 12:00:00 pm27/03/2019 12:00:00.000 或类似的东西。当数据库或编程语言将该字符串视为日期对象时,它看起来像 123465789.123465798,这通常是自系统组件使用的任何纪元以来的特定秒值。 Epoch 是完全不同的话题。

由于长小数作为日期并不是真正可读的,因此您的语言必须执行掩码以在两种表示形式之间来回转换。

您想记住您使用的是哪一段代码来进行屏蔽。通常,屏蔽是为了显示,但您可能还需要它在插入之前将字符串转换为数据库中的日期可读对象。因此,您需要检查您的 Java 脚本是否未对表单中的值执行任何操作,您的 ColdFusion 是否未对该 Java 脚本字符串执行任何操作,以及您的数据库不会进一步更改 ColdFusion 字符串。

我不确定 Bootstrap 的 datapicker 使用什么来解释日期字符串,或者它是否最终向您的 ColdFusion 发送了一个奇怪的字符串,但我知道 CF11 使用不同的掩码,具体取决于关于您正在使用的功能。 DateFormat() 不关心你使用什么大小写,但 DateTimeFormat() 关心。它依赖于其底层 Java SimpleDateFormat 的掩码定义,它将 yY 解释为不同的掩码,意味着不同的东西。

最大的痛苦是,如您所见,它只会在一年结束时出现几天,因为一年永远不会正好由 52 周组成。所以我们有另一种类型的日期,称为 WeekYear,或 SimpleDateFormat 掩码中的 Y。它本质上是基于周的年份(Ww)。因此,在一年的开始和结束的短短几天内,日历年不会等于星期年。对于一年中的其他 358 天左右,它们将是相同的。由于新年和新年前夜通常是非工作假期,因此 非常容易 忽略。因此,从本质上讲,您的代码在过去几年中一直没有正常工作;你只是没有理由注意到。好玩吧?

一个简单的例子,参见:https://trycf.com/gist/5cb651559e28e5cbdecdb57b959c3c18/acf11?theme=monokai

如果您注意到,dateFormat()timeFormat() 都会掩盖它们 "technically" 应该做的事情。您也可以获得 timeFormat() 以将掩码应用于字符串的 date 部分。他们不应该那样工作。

正如我在多个地方所说的那样,日期处理(几乎任何语言)都是我的烦恼。这是一个会让你想拔头发的话题。也可能是坐在你旁边的任何人的头发。 绝对 编写您正在调试的日期处理代码的人的头发。这完全是一个代码狂热的话题。

无论如何,如果您想查看其他一些示例,我之前已经写过几次,并且可能会再次这样做。谢谢你把我拉回到这个疯狂的兔子洞里。

https://codefumonkey.blogspot.com/2016/02/date-masking-inconsistency.html https://codefumonkey.blogspot.com/2016/10/more-date-masking.html

注意:更新的 CF 版本更改了某些日期函数中的掩码行为。它们在 CF2018 中不区分大小写,因此使用 yyyyYYYY 并不重要。但是帮自己一个忙,使用 yyyy,因为您知道 CF 仍然建立在 Java 之上。但是,还有一些其他框架期望 YYYY 而不是 yyyy,因此记住您用来应用掩码的语言仍然非常重要。如果您不需要查看日期值并可以继续使用日期对象,请保持这种状态,而不是将其设为可读字符串。