Java 日历实例递增DAY_OF_MONTH作为递减(仅)小时或分钟的副作用



我有一个未完成的Android应用程序,其中包含一个主活动,带有TimePicker(@+id/tyme(,DatePicker(@+id/date(和TextView(@+id/dropTime(,用于显示类似"日期时间"的数据,由于某种原因,我需要两个视图来指定。

由于 Javadocs 不推荐所有从Date实例中提取 DateTime 字段类型值的尝试,因此我想使用Calendar类来表示用户选择的年、月、日、小时、分钟、秒的组合。 我发现我经常(但并非总是(无法在不同时增加月份中的日期字段的情况下减少小时或分钟字段。 这是我DatePicker的事件处理程序:

date = (DatePicker) findViewById(R.id.date);
// h/t O'one https://stackoverflow.com/a/34952495/948073
date.init(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH),
new DatePicker.OnDateChangedListener() {
@Override
public void onDateChanged(DatePicker datePicker, int y, int m, int d) {
System.out.println("onDateChanged(tp,"+y+","+m+","+d+")");
calendar.set(Calendar.YEAR, y);
calendar.set(Calendar.MONTH, m);
calendar.set(Calendar.DAY_OF_MONTH, d);
updateDropTime();
}
}
);

还有TimePicker. 请注意 y/m/d 字段的显式备份和恢复,徒劳地试图消除 h:m:s 更改期间 y:m:d 的可疑交叉污染:

private TimePicker time;
dropTime = (TextView) findViewById(R.id.dropTime);
updateDropTime();
time = (TimePicker) findViewById(R.id.tyme);

time.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
public void onTimeChanged(TimePicker tp, int h, int m) {
System.out.println("onTimeChanged(tp,"+h+","+m+")");
// Save state of y/m/d portion of calendar
int y = calendar.get(Calendar.YEAR);
int mo = calendar.get(Calendar.MONTH);
int d = calendar.get(Calendar.DAY_OF_MONTH);
// Set h and m fields of calendar based on user input
calendar.set(Calendar.HOUR, h);
calendar.set(Calendar.MINUTE, m);
// Restore state of y/m/d fields
calendar.set(Calendar.YEAR, y);
calendar.set(Calendar.MONTH, mo);
calendar.set(Calendar.DAY_OF_MONTH, d);
// In theory y/m/d portion of datetime should be unchanged
updateDropTime();
}
});

这两个事件处理程序都调用updateDropTime(),如下所示:

private void updateDropTime() {
String disp = DateFormat.getDateTimeInstance().format(calendar.getTimeInMillis());
dropTime.setText(disp);
}

我怀疑方法链中导致disp值的某些东西是看似混乱行为发生的地方,因为我认为我已经系统地消除了对日期字段的任何更改,这些更改可能是时间字段更改的副作用。

这一行是错误的:

calendar.set(Calendar.HOUR, h);

相反,您希望:

calendar.set(Calendar.HOUR_OF_DAY, h);

您进入onTimeChanged()h是 24 小时制的一天中的小时。Calendar.HOUR表示 AM 或 PM 内的小时,即 12 小时制。

这如何导致您的问题?示例:原始时间为 20:25(如果您愿意,也可以选择晚上 8:25(。用户将其更改为 13:28(下午 1:28(。将Calendar.HOUR设置为 13。由于原始时间在 PM 中,并且您不更改此时间,因此您有效地将时间设置为 13:28 PM。这是无稽之谈,但Calendar不在乎,它只是将其解释为第二天凌晨1:28点。设置日期无济于事,因为在执行此操作时,尚未计算字段,因此在内部,时间仍然是正确日期的下午 13:28。只有当你最终调用getTimeInMillis()时,才会计算所有字段,检测到溢出并增加日期。

Calendar默认宽松

如果您希望收到有关此类错误的通知(我们都不时犯的错误(,请在创建Calendar对象后调用setLenient(false)。这将导致它不接受超出范围的值,例如 13 表示HOUR.

java.time

如果你根本不想打扰Calendar类,你肯定离第一个还很远,还有一个更好、更对程序员友好的选择。现代 Java 日期和时间 API 内置于 Java 8 及更高版本中,在 Android 上,您可以在 ThreeTenABP 中使用它,请参阅如何在 Android Project 中使用 ThreeTenABP。我建议将日期保留在LocalDate对象中,将一天中的时间保留在LocalTime中,以便用户可以独立更新每个对象,而不会有交叉污染的风险。只有在updateDropTime(),您才会使用LocalDate.atTime()将两者组合成一个LocalDateTime,然后使用DateTimeFormatter将其格式化为所需的显示格式。

public void onTimeChanged(TimePicker tp, int h, int m) {
System.out.println("onTimeChanged(tp," + h + "," + m + ")");
time = LocalTime.of(h, m);
updateDropTime();
}

更新可能如下所示:

private void updateDropTime() {
String disp = date.atTime(time)
.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT));
dropTime.setText(disp);
}

相关内容

  • 没有找到相关文章

最新更新