Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/firebase/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Calendar实例增加每月的第天,作为减少(仅)小时或分钟的副作用_Java_Android_Date_Datetime_Calendar - Fatal编程技术网

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
,到目前为止,我可以随心所欲地旋转小时和分钟微调器,并且日期字段非常稳定。请将以上评论作为回答。