繁体   English   中英

Java Calendar实例增加DAY_OF_MONTH作为递减(仅)HOUR或MINUTE的副作用

[英]Java Calendar instance increments DAY_OF_MONTH as a side effect of decrementing (only) HOUR or MINUTE

我有一个未完成的Android应用程序 ,主要活动有TimePicker@+id/tyme ), DatePicker@+id/date )和TextView@+id/dropTime ),用于显示类似“DateTime”的数据由于某种原因,我需要指定两个视图。

因为Javadocs不赞成从Date实例中提取DateTime-field-type值的所有尝试,所以我想使用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);

h你得到onTimeChanged()是在24小时时钟一天的小时。 Calendar.HOUR表示AM或PM内的小时,即12小时制。

这怎么会导致你的问题? 示例:原始时间为20:25(如果您愿意,则为8:25 PM)。 用户将其更改为13:28(1:28 PM)。 您将Calendar.HOUR设置为13.由于原始时间是在PM并且您不更改此项,因此您实际上将时间设置为下午13:28。 这是胡说八道,但Calendar并不关心,它只是将其解释为第二天凌晨11:28分。 设置日期并没有帮助,因为当你这样做时,字段尚未计算,因此内部时间仍然是正确的一天下午13:28。 只有在最后调用getTimeInMillis() ,才会计算所有字段,检测到溢出并增加日期。

Calendar是默认的宽松

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

java.time

如果您根本不想使用Calendar类,那么您肯定远离第一个,并且有一个更好,更程序友好的替代方案。 现代Java日期和时间API内置于Java 8及更高版本中,在Android上您可以在ThreeTenABP 中使用它,请参阅如何在Android项目中使用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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM