英文:
Parse Date String Return Wrong Month
问题
以下是翻译好的内容:
我尝试解析日期字符串,但始终得到错误的月份。以下是我的代码。
这是从日历中选择日期的代码
@OnClick(R.id.tedit_tgllahir_addnew) void showTimeDialog(){
calendar = Calendar.getInstance();
year = calendar.get(Calendar.YEAR);
month = calendar.get(Calendar.MONTH);
date = calendar.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(AddDataForNewUserActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
etTgl.setText(String.format("%02d/%02d/%02d", year, month+1, dayOfMonth));
}
}, year, month, date);
datePickerDialog.show();
}
以下是在我想要解析数据时的代码
birth = LocalDate.of(list.getTglLahirAnak().getYear() + 1900, list.getTglLahirAnak().getMonth(), list.getTglLahirAnak().getDate());
int year = Period.between(birth, LocalDate.now()).getYears();
int month = Period.between(birth, LocalDate.now()).getMonths();
int totalBulan = year * 12 + month;
无论我从日历中输入日期,它总是显示错误的月份。例如,我选择了五月,但系统读取为四月。感谢所有愿意帮助的人。
英文:
I try to parse date string but always get wrong month. Here's my code.
This is code to select date from calender
@OnClick(R.id.tedit_tgllahir_addnew) void showTimeDialog(){
calendar = Calendar.getInstance();
year = calendar.get(Calendar.YEAR);
month = calendar.get(Calendar.MONTH);
date = calendar.get(Calendar.DAY_OF_MONTH);
DatePickerDialog datePickerDialog = new DatePickerDialog(AddDataForNewUserActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
etTgl.setText(String.format("%02d/%02d/%02d", year, month+1, dayOfMonth));
}
}, year, month, date);
datePickerDialog.show();
}
and this is when i want to parse data
birth = LocalDate.of(list.getTglLahirAnak().getYear() + 1900, list.getTglLahirAnak().getMonth(), list.getTglLahirAnak().getDate());
int year = Period.between(birth, LocalDate.now()).getYears();
int month = Period.between(birth, LocalDate.now()).getMonths();
int totalBulan = year * 12 + month;
Whenever I input date from the calender, it always shows the wrong month. For example I choose May but in the system read April. Thanks to all who are willing to help.
答案1
得分: 1
我从你的问题中了解到你正在使用JSR-310的后移版本,可能是Android版的ThreeTenABP。如果是这样,请完全采用它,并放弃使用设计不佳且过时的Calendar
和Date
类。
即使使用Date
类是由于你无法控制的外部原因,你仍必须避免使用其中的弃用方法,包括getYear()
、getMonth()
和getDate()
。当接收到一个Date
并将其转换为LocalDate
时,你正在尝试正确的事情。首先使用后移版本中的DateTimeUtils
进行转换。
但让我们从头开始。在设置日期选择器的初始日期时,请使用LocalDate
,而不要使用老式的Calendar
类。我没有编译代码,所以如果有错别字,请谅解。
LocalDate today = LocalDate.now(ZoneId.systemDefault());
year = today.getYear();
month = today.getMonthValue(); // 自然上从1开始
date = today.getDayOfMonth();
DatePickerDialog datePickerDialog = new DatePickerDialog(AddDataForNewUserActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
// 以后再回到这部分
}
}, year, month - 1, date); // 传递基于0的月份
当用户从日历/日期选择器中选择日期时,请不要将其存储为字符串。将其存储为LocalDate
对象。这样可以避免以后进行任何解析,并且你的代码还显示出你需要一个LocalDate
。显然,如果你想向用户显示所选日期,请将日期格式化为字符串(仅限此目的)。使用DateTimeFormatter
进行格式化:
private static final DateTimeFormatter dateFormatter
= DateTimeFormatter.ofPattern("yy/MM/dd");
现在我们继续:
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
// 将所选日期存储在稍后可以找到的位置
selectedLocalDate = LocalDate.of(year, month + 1, dayOfMonth);
// 显示给用户
String formattedDate = selectedLocalDate.format(dateFormatter);
etTgl.setText(formattedDate);
}
现在,计算月龄不再有问题:
birth = selectedLocalDate;
long totalBulan = Period.between(birth, LocalDate.now(ZoneId.systemDefault()))
.toTotalMonths();
如果你无法控制从list.getTglLahirAnak()
获取的内容,从Date
转换为LocalDate
的方法如下:
Date oldfashionedDate = list.getTglLahirAnak();
birth = DateTimeUtils.toInstant(oldfashionedDate)
.atZone(ZoneId.systemDefault())
.toLocalDate();
现在,年龄的计算与之前一样进行。
你的代码出了什么问题?
就像过时的Calendar
一样,被弃用的Date.getMonth()
将月份从0表示,从1代表一月到11代表十二月。因此,如果你选择了五月的一个日期,list.getTglLahirAnak().getMonth()
会返回4,表示五月。当你将这个值传递给LocalDate
,它以自然且合理的月份编号,会得到四月。
英文:
I gather from your question that you are using the backport of JSR-310, probably the Android edition, ThreeTenABP. If so, go all-in on that and drop the use of the poorly designed and long outdated Calendar
and Date
classes.
Even if the use of the Date
class is dictated from outside of your control, you must still stay away from its deprecated methods including getYear()
, getMonth()
and getDate()
. You are trying the good thing when receiving a Date
and converting it to a LocalDate
first thing. Use DateTimeUtils
from the backport for a first conversion.
But let’s take it from the top. Use LocalDate
for setting the initial date of your date picker. Don’t use the old-fashioned Calendar
class. I have not compiled the code, so please forgive if there’s a typo.
LocalDate today = LocalDate.now(ZoneId.systemDefault());
year = today.getYear();
month = today.getMonthValue(); // naturally 1-based
date = today.getDayOfMonth();
DatePickerDialog datePickerDialog = new DatePickerDialog(AddDataForNewUserActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
// will return to this part later
}
}, year, month - 1, date); // Pass 0-based month
When the user selects a date from the calendar/date picker, don’t store it as a string. Store it as a LocalDate
object. This saves you from doing any parsing later, and your code also shows that you need a LocalDate
. Obviously if you want to show the selected date to the user, format the date into a string for that purpose (only). Use a DateTimeFormatter
for formatting:
private static final DateTimeFormatter dateFormatter
= DateTimeFormatter.ofPattern("yy/MM/dd");
Now we go:
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
// Store the selected date somewhere you can find it later
selectedLocalDate = LocalDate.of(year, month + 1, dayOfMonth);
// Display to the user
String formattedDate = selectedLocalDate.format(dateFormatter);
etTgl.setText(formattedDate);
}
Now the calculation of age in months poses no problem anymore:
birth = selectedLocalDate;
long totalBulan = Period.between(birth, LocalDate.now(ZoneId.systemDefault()))
.toTotalMonths();
If you cannot control what you get from list.getTglLahirAnak()
, the conversion from Date
to LocalDate
is:
Date oldfashionedDate = list.getTglLahirAnak();
birth = DateTimeUtils.toInstant(oldfashionedDate)
.atZone(ZoneId.systemDefault())
.toLocalDate();
Now the calculation of age proceeds as before.
What went wrong in your code?
Just like the outdated Calendar
also the deprecated Date.getMonth()
numbers the months from 0 for January through 11 for December. So if you pick a date in May, list.getTglLahirAnak().getMonth()
returns 4 for May. When you feed this into a LocalDate
with its natural and sensible month numbering, it gives you April.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论