意外的日期计算结果

时间:2017-11-13 07:38:16

标签: java time localdate

我有一种方法可以在Java中查看日历,该日历可以按年份,星期几和周数来计算日期。

现在,当我计算2017年的日期时,一切正常。但是,当我计算2018年1月的日期时,需要2017年的日期。

我的代码看起来像

INSERT INTO "orders" ("company_id", "price", "quantity", "order_date", "delivery_date", "created_at", "updated_at", "discount", "order_number", "invoice_number", "type", "dc_number", "user_id", "due_date", "status_value_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) RETURNING "id"  [["company_id", 13], ["price", 11000.0], ["quantity", 10], ["order_date", 2017-11-12 19:00:00 UTC], ["delivery_date", 2017-11-12 19:00:00 UTC], ["created_at", 2017-11-13 06:06:52 UTC], ["updated_at", 2017-11-13 06:06:52 UTC], ["discount", 0.0], ["order_number", 26], ["invoice_number", 26], ["type", "RegisteredOrder"], ["dc_number", "10"], ["user_id", 1], ["due_date", 2017-12-12 19:00:00 UTC], ["status_value_id", 9]]
SQL (16.0ms)  INSERT INTO "order_products" ("order_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["order_id", 90], ["created_at", 2017-11-13 06:06:52 UTC], ["updated_at", 2017-11-13 06:06:52 UTC]]

结果是2018-01-02,应该是2018-01-01。这怎么可能?

2 个答案:

答案 0 :(得分:12)

调用方法的顺序似乎很重要 你通过降序时间粒度(年,星期和星期几)来调用它们,你得到了正确的结果:

long weekNumber = 1;
long dayOfWeek = 1;
int year = 2018;

LocalDate desiredDate = LocalDate.now()
    .withYear(year)
    .with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber)
    .with(ChronoField.DAY_OF_WEEK, dayOfWeek );

System.out.println(desiredDate);
  

2018年1月1日

请注意,问题来源于:

.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber)

根据当前年份设置周数(1 to 53如果您使用LocalDate更改年份,那么Java .withYear(year) API无法调整此值,因为周数信息未保存在LocalDate实例中。

您确实可以在LocalDate实施中看到LocalDate个实例仅由3个字段定义:yearmonthday

public final class LocalDate
        implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {
    ...
    private final int year;
    /**
     * The month-of-year.
     */
    private final short month;
    /**
     * The day-of-month.
     */
    private final short day;
    ...
}

所以准确地说,重要的是:

之前调用

.withYear(year)

.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber);

答案 1 :(得分:1)

我想提到的是,LocalDate还有另一个问题(?)。

此代码还会产生错误的结果:


<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>

<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>

<h2>Comments</h2>
<%= render @article.comments %>

<h2>Add a comment:</h2>
<%= form_with(model: [ @article, @article.comments.build ], local: true) do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>

如果将 int jahr = Integer.parseInt(str[0]); int woche = Integer.parseInt(str[1]); LocalDate year = LocalDate.of(jahr, 1, 1); LocalDate week = year.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, woche); LocalDate day = week.with(wochentag); return day; 变量的创建更改为

year

代码返回预期结果。看来构造LocalDate的方式很重要。我猜时区在“ .of()”版本中被省略了。