Java Calendar实例增加每月的第天,作为减少(仅)小时或分钟的副作用
我的主要活动是一个Java Calendar实例增加每月的第天,作为减少(仅)小时或分钟的副作用,java,android,date,datetime,calendar,Java,Android,Date,Datetime,Calendar,我的主要活动是一个时间选择器(@+id/tyme),一个日期选择器(@+id/date),以及一个文本视图(@+id/dropTime),用于显示类似“日期时间”的数据,出于某种原因,我需要两个视图来指定 由于Javadocs反对从Date实例中提取日期时间字段类型值的所有尝试,因此我想使用Calendar类来表示用户选择的年、月、日、时、分、秒的组合。我发现我经常(但并非总是)不能在不同时增加月日字段的情况下减少小时或分钟字段。下面是我的日期选择器的事件处理程序: date =
时间选择器(@+id/tyme
),一个日期选择器(@+id/date
),以及一个文本视图(@+id/dropTime
),用于显示类似“日期时间”的数据,出于某种原因,我需要两个视图来指定
由于Javadocs反对从Date
实例中提取日期时间字段类型值的所有尝试,因此我想使用Calendar
类来表示用户选择的年、月、日、时、分、秒的组合。我发现我经常(但并非总是)不能在不同时增加月日字段的情况下减少小时或分钟字段。下面是我的日期选择器的事件处理程序
:
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();
}
}
);
和时间选择器
。注意,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();
}
});
这两个事件处理程序都调用updatedOptime()
,如下所示:
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小时制的小时<代码>日历。小时
表示上午或下午的小时,即12小时时钟上的小时
这怎么会导致您的问题?示例:最初的时间是20:25(如果您愿意,也可以是晚上8:25)。用户将其更改为13:28(下午1:28)。您将日历小时设置为13。因为原来的时间是在下午,你没有改变这一点,你有效地将时间设置为下午13:28。这是胡说八道,但是Calendar
不在乎,它只是把它解释为1:28
AM第二天。设置日期没有帮助,因为在您这样做的时候,字段还没有计算出来,所以在内部时间仍然是正确日期的下午13:28。只有在最后调用getTimeInMillis()
时,才会计算所有字段,检测到溢出并增加日期
日历
默认为宽松
如果您希望收到有关此类错误的通知(我们都会不时发生),请在创建Calendar
对象后,在该对象上调用setLenient(false)
。这将导致它不接受超出范围的值,如小时的13
java.time
如果您根本不想为Calendar
类操心,那么您肯定离第一个类很远,而且还有一个更好、更方便程序员的替代方案。现代Java日期和时间API内置于Java8及更高版本中,在Android上,您可以在中使用它,请参阅。我建议将日期保存在LocalDate
对象中,将一天中的时间保存在LocalTime
中,这样用户就可以独立地更新每个时间,而不存在交叉污染的风险。只有在updatedOptime()
中,您才能使用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);
}
奇怪的行为是确定性的吗?我的意思是,你能找到一个示例日历值和示例h
和m
值,它们始终产生月日字段的增量吗?calendar
在更改其值时并不总是计算所有字段。我想这可能与您观察到的行为有关,但又不是因为调用getTimeInMillis()
应该计算字段。请参阅示例。我们可以排除并发问题吗Calendar
不是线程安全的。它可能与您的问题无关:您进入onTimeChanged
的h
是24小时时钟上的小时,因此您需要Calendar.set(Calendar.hour\u of u day,h)
。将HOUR
更改为HOUR\u OF_DAY
,到目前为止,我可以随心所欲地旋转小时和分钟微调器,并且日期字段非常稳定。请将以上评论作为回答。