问题描述
我在 Rails 应用中遇到了向 moment 日期添加秒数的问题。我将 Stimulus 用于 JS,但这与问题的原因无关。
我使用 Rails 表单构建器使用这些 options_for_select
生成了一个选择表单输入:
[["1 day",1.day],["3 days",3.days],["7 days",1.week],["14 days",2.weeks],["1 month",1.month],["3 months",3.months],["6 months",6.months],["1 year",1.year]]
这会导致一个看起来像这样的选择:
<select class="form-control" data-admin--reports-form-target="sendFrequencySelect"
<option value="86400">1 day</option>
<option value="259200">3 days</option>
<option value="604800">7 days</option>
<option value="1209600">14 days</option>
<option value="2629746">1 month</option>
<option value="7889238">3 months</option>
<option selected="selected" value="15778476">6 months</option>
<option value="31556952">1 year</option>
</select>
我有一些 JS 获取所选选项的值并将该秒数添加到时刻日期,然后将不同输入的值设置为该计算产生的新时刻日期:
let finalRunAt = moment(this.lastGeneratedTimestampInputTarget.value,"YYYY-MM-DD HH:mm");
let secondsToAdd = parseInt(this.sendFrequencySelectTarget.value);
finalRunAt.add(secondsToAdd,"seconds");
this.finalRunTimestampInputTarget.value = finalRunAt.format("YYYY-MM-DD HH:mm");
这可以正常工作...直到您达到 1 个月或更长时间。以下是开始日期 2021-02-25 12:00
的计算结果:
选择选项 | 将秒添加到开始日期的结果 |
---|---|
1 天 | 2021-02-26 12:00 |
3 天 | 2021-02-28 12:00 |
7 天 | 2021-03-04 12:00 |
14 天 | 2021-03-11 12:00 |
1 个月 | 2021-03-27 23:29 |
3 个月 | 2021-05-27 20:27 |
6 个月 | 2021-08-27 03:54 |
1 年 | 2022-02-25 17:49 |
我一直在尝试对奇怪的(粗体)结果进行逆向工程。是什么导致了这些结果? Rails 认为 1 个月和哪个时刻认为 1 个月之间是否存在差异?
解决方法
尽管我不确定 Rails 为何使用 2629746
作为 1.month
的表示形式(以秒为单位)的细微差别,但我已经针对这种情况实施了一种解决方法。
我想保持由 Rails 生成的选择输入,因为它生成的值(在问题中列出)在 Rails 端工作得很好。也就是说,我可以无缝地使用该选择来选择要用作 ActiveSupport::Duration
的间隔。出于这个原因,我不想更改选择输入。
相反,我编写了一个简单(虽然有点笨拙)的函数来根据 select 的值执行正确的矩操作:
addRailsSecondsStringToMoment(seconds_string,moment) {
switch (seconds_string) {
case "86400":
moment.add(1,"days");
break;
case "259200":
moment.add(3,"days");
break;
case "604800":
moment.add(7,"days");
break;
case "1209600":
moment.add(14,"days");
break;
case "2629746":
moment.add(1,"months");
break;
case "7889238":
moment.add(3,"months");
break;
case "15778476":
moment.add(6,"months");
break;
case "31556952":
moment.add(1,"years");
break;
}
}
然后我可以这样称呼它:
this.addRailsSecondsStringToMoment(this.sendFrequencySelectTarget.value,finalRunAt);
... 其中 finalRunAt
是一个 moment
对象。可能会更漂亮一点,但它有效。如果有人发布了一个更性感的解决方案,我很乐意接受,尤其是如果它提供了一些关于 Rails 为何使用它所使用的秒值的信息。