【问题标题】:Calendar won't return date with AM/PM日历不会返回带有 AM/PM 的日期
【发布时间】:2020-05-12 12:45:22
【问题描述】:

我想要 AM/PM 格式的日期。示例建议将 SimpleDateFormat 与 a 或 aa 一起使用,但这根本不适合我。

首先我设定了日期。然后我将视图设置为开始时间可见。

结果是 2020 年 5 月 20 日星期三 01:00:00 EDT 的格式,需要类似于 2020 年 5 月 20 日星期三 01:00:00 AM EDT 的格式

这适用于 setStartTime 方法中的 calendar.getTime()。仅包含第一种方法是因为所选日期作为全局变量链接。问题在于第二种方法。

我可以手动将最终日期更改为字符串并将其转换回来,但我不想增加不必要的复杂性。我想找出为什么 Calendar 不会成功,因为这应该是非常基本的。

最后,我的目标是将日期添加到 firebase。它必须在 Android、IOS 和 Web 之间保持统一。因此,我需要日期采用这种确切的格式。

代码如下:

    SimpleDateFormat serviceSETimeFormat = new SimpleDateFormat("MMM dd, yyyy HH:mm aa");

public void setStartDay(View view)
{
    Calendar calendar = Calendar.getInstance();
    DatePickerDialog picker = new DatePickerDialog(ServiceCreation.this,
        new DatePickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                GregorianCalendar mCal = new GregorianCalendar(year, monthOfYear, dayOfMonth);
                Date dateForDisplay = mCal.getTime();
                int startHourIndex = getThirdSpaceIndex(dateForDisplay.toString());
                //SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
                serviceSETimeFormat.setCalendar(mCal);
                Date dateFormatted = null;
                try{
                    dateFormatted= serviceSETimeFormat.parse(serviceSETimeFormat.format(mCal.getTime()));
                    currBaseStartDate=dateFormatted;
                }
                catch(ParseException p){
                    Log.wtf("SC","Parse exc34");
                }
                Log.wtf("SC","Here is orig date: "+dateFormatted);
                //Don't show hh/mm/ss (these are held as 0)
                startDayView.setText(dateForDisplay.toString().substring(0,startHourIndex));
                startEndTimeWrapper.setVisibility(View.VISIBLE);
            }
        }, calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH),calendar.get(Calendar.DAY_OF_MONTH));
    long currentTime = new Date().getTime();
    picker.getDatePicker().setMinDate(currentTime);
    picker.show();
}


public void setStartTime(View view) {
    TimePickerDialog mTimePicker = new TimePickerDialog(ServiceCreation.this,
        android.R.style.Theme_Holo_Light_Dialog_NoActionBar, new TimePickerDialog.OnTimeSetListener() {
        @Override
        public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) {
            String minuteAsS =  Integer.toString(selectedMinute);
            if(minuteAsS.length()==1){
                minuteAsS="0"+minuteAsS;
            }
            if(selectedHour==0){
                startTimeView.setText((selectedHour+12)+":"+minuteAsS+" AM");
            }
            else if(selectedHour<12){
                startTimeView.setText(selectedHour+":"+minuteAsS+" AM");
            }
            else if(selectedHour==12){
                startTimeView.setText((selectedHour)+":"+minuteAsS+" PM");
            }
            else{
                startTimeView.setText((selectedHour-12)+":"+minuteAsS+" PM");
            }

            (findViewById(R.id.endTimeWrapper)).setVisibility(View.VISIBLE);
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(currBaseStartDate);
            calendar.set(Calendar.MINUTE, selectedMinute);
            Log.wtf("SC","Hour before condition: "+selectedHour);
            if(selectedHour>=12){
                if(selectedHour!=12){
                    Log.wtf("SC","Decrementing hour");
                    selectedHour-=12;
                }
                Log.wtf("SC","Hour set: "+selectedHour);
                calendar.set(Calendar.AM_PM,Calendar.PM);
                calendar.set(Calendar.HOUR_OF_DAY,selectedHour);
            }
            else{
                calendar.set(Calendar.AM_PM,Calendar.AM);
                calendar.set(Calendar.HOUR_OF_DAY,selectedHour);
            }
            startTime=calendar.getTime();
            Log.wtf("SC","Here is orig start time: "+startTime);
            try{
                startTime=serviceSETimeFormat.parse(serviceSETimeFormat.format(startTime));
                Log.wtf("SC","Here is parsed start time: "+startTime);
            }
            catch(ParseException e){
                Log.wtf("SC","START DATE PARSE EXCEPTION");
            }
        }
    }, 12, 0, false);
    mTimePicker.setTitle("Select Start Time: ");
    mTimePicker.show();
}

【问题讨论】:

标签: android calendar simpledateformat


【解决方案1】:

三点:

  1. 即使在 Android 上,甚至在 API 级别低于 26 的情况下,也可以考虑使用 java.time,这是现代 Java 日期和时间 API。 CalendarGregorianCalendarSimpleDateFormatDate 是令人困惑的、设计不佳且长期过时的类。现代 API 更易于使用。
  2. 您不希望CalendarDate 带有上午或下午。您希望将模型和对用户的演示分开。在模型中,您需要 LocalDateTime 或其他适当的日期时间对象,并且您不想担心它的格式,无论它使用 12 小时还是 24 小时时钟。为了向您的用户显示日期和时间,您需要以适合您用户的格式(包括 AM 或 PM)在 string 中显示日期和时间。这也是为什么您的视图有setText 方法而没有setDate 方法的原因。
  3. 不能存在具有 AM/PM 格式的 Date。你问的是不可能的事。

java.time 和 ThreeTenABP

从您的三个整数中构造一个LocalDate 对象,分别代表年、月和日:

    int year = 2020;
    int monthOfYear = Calendar.MAY; // Don’t use Calendar, though
    int dayOfMonth = 11;

    LocalDate date = LocalDate.of(year, monthOfYear + 1, dayOfMonth);
    System.out.println(date);

输出:

2020-05-11

我相信您的日期选择器从 0 代表一月到 11 代表十二月。所以我们需要在月份数字上加 1 以转换为人类和LocalDate 月份的方式。我只使用 Calendar 类中的常量将变量初始化为从 0 开始的月份数,不要在代码中这样做,因为值来自数据选择器。 Calendar 使用相同的疯狂编号。

要向用户显示日期,请使用格式化程序将其格式化为字符串:

    DateTimeFormatter dateFormatter = DateTimeFormatter
            .ofLocalizedDate(FormatStyle.MEDIUM)
            .withLocale(Locale.US);
    String dateForDisplay = date.format(dateFormatter);
    System.out.println(dateForDisplay);

2020 年 5 月 11 日

提供适当的区域设置,或省略对withLocale() 的调用以依赖设备的区域设置。

当用户选择时间时:

    int selectedHour = 1;
    int selectedMinute = 0;

    LocalTime selectedTime = LocalTime.of(selectedHour, selectedMinute);
    LocalDateTime dateTime = date.atTime(selectedTime);
    System.out.println(dateTime);

2020-05-11T01:00

时间的格式可以与我们对日期的处理方式非常相似:

    DateTimeFormatter timeFormatter = DateTimeFormatter
            .ofLocalizedTime(FormatStyle.MEDIUM)
            .withLocale(Locale.US);
    String timeForDisplay = selectedTime.format(timeFormatter);
    System.out.println(timeForDisplay);

凌晨 1:00:00

问题:java.time 不需要 Android API 26 级吗?

java.time 在较旧和较新的 Android 设备上都能很好地工作。它只需要至少 Java 6

  • 在 Java 8 及更高版本以及更新的 Android 设备(从 API 级别 26 起)中,现代 API 是内置的。
  • 在非 Android Java 6 和 7 中,获取 ThreeTen Backport,这是现代类的后向端口(JSR 310 的 ThreeTen;请参阅底部的链接)。
  • 在(较旧的)Android 上使用 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。并确保从 org.threeten.bp 导入日期和时间类以及子包。

链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多