【问题标题】:How to get another Calendar result from same instance?如何从同一实例中获取另一个日历结果?
【发布时间】:2014-04-18 02:15:02
【问题描述】:

我正在尝试创建一个包含假期和日期(均为字符串)的 ArrayList,然后将日期转换为日历,获取星期几(使用 DAY_OF_WEEK)和/或按日期/名称排序,但由于某种原因我得到了列表中的每个项目都具有相同的结果(日历)。

这是我的代码:

 public static ArrayList listOfHolidays = new ArrayList();

        Holidays.holidaysList.add(new Holidays("Sukkot", "09/10/2014"));
        Holidays.holidaysList.add(new Holidays("Hanukkah", "17/12/2014"));
        Holidays.holidaysList.add(new Holidays("Purim", "16/03/2014"));

假期班:

日历日历 = Calendar.getInstance(); @覆盖 公共字符串 toString() { //DayOfWeek 只是天数(字符串)的枚举 return holidayName + " 落在 " + DayOfWeek.values()[Calendar.DAY_OF_WEEK - 1]; // 这里我每次都得到同一天 } @覆盖 public int compareTo(假期另一个){ 如果(MainActivity.sortByName == true){ return holidayName.compareToIgnoreCase(another.holidayName); } return convertStringToCal() - another.convertStringToCal(); } 私有 int convertStringToCal() { int 年、月、日; day = Integer.valueOf(holidayDate.substring(0, 2)); 月 = Integer.valueOf(holidayDate.substring(3, 5)); 年 = Integer.valueOf(holidayDate.substring(6, 10)); 日历 = Calendar.getInstance(); calendar.set(年、月、日); return (int) calendar.getTimeInMillis(); }

我打电话

Collections.sort()
从一个radioButton 方法中进行排序。

【问题讨论】:

  • 仅供参考,java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 等麻烦的旧日期时间类现在已被 java.time 类所取代。在ThreeTen-Backport 项目中,大部分 java.time 功能都向后移植到 Java 6 和 Java 7。在ThreeTenABP 项目中进一步适用于早期的Android。见How to use ThreeTenABP…

标签: java android arraylist calendar


【解决方案1】:

我看到它可能不起作用的多种原因。

首先,我不知道您是否省略了 Holidays 类的部分代码,但您实际上从未将日历对象设置为 convertStringToCal() 方法,但我不知道在构造函数中是否也调用了此方法.

其次,很可能是您的问题:

@Override
    public String toString() {
    //DayOfWeek is just an enum of days (strings)
        return holidayName + " falls on "
                                        // Here you are using the constant Calendar.DAY_OF_WEEK
                    + DayOfWeek.values()[Calendar.DAY_OF_WEEK - 1]; // Here i get the same day each time
    }

它实际上应该是这样的:

@Override
    public String toString() {
    //DayOfWeek is just an enum of days (strings)
        return holidayName + " falls on "
                    + DayOfWeek.values()[calendar.get(Calendar.DAY_OF_WEEK)]; // Now you won't get the same day every time. :)
    }

一些补充说明:

我会使用Date 对象来保存日期,并使用SimpleDateFormat 将字符串转换为日期,反之亦然。

如果您使用这两个,您的 Holidays 类将如下所示:

public class Holidays {

        private final Calendar calendar = Calendar.getInstance();
        private final String holidayName;

        public Holidays(String holidayName, Date date) {
            this.holidayName = holidayName;
            this.calendar.setTime(date);
        }

        @Override
        public int compareTo(Holidays another) {
            // Generally you should avoid passing information statically between Activities
            if(MainActivity.sortByName == true) {
                    return holidayName.compareToIgnoreCase(another.holidayName);
            }
            return getTimeInMillis() - another.getTimeInMillis();
        }

        public long getTimeInMillis() {
            return this.calendar.getTimeInMillis();
        }

        @Override
        public String toString() {
        //DayOfWeek is just an enum of days (strings)
            DayOfWeek day = DayOfWeek.values()[calendar.get(Calendar.DAY_OF_WEEK)]; // Now you won't get the same day every time. :)
            return String.format("%s falls of %s", this.holidayName, day);
        }

    }

您可以像这样创建Date 对象:

// Create date objects with calendar.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2014);
calendar.set(Calendar.MONTH, 3);
calendar.set(Calendar.DAY_OF_MONTH, 27);
Date date = calendar.getTime();

像 new Date(year, month, day) 这样的 Date 对象的构造函数已被弃用,不应使用。始终使用日历实例来创建日期对象。

使用SimpleDateFormat,您可以像这样转换StringDate 对象:

// The String pattern defines how date strings are parsed and formated
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

String dateString = "09/10/2014";

// Convert a String to Date
Date dateFromDateString = sdf.parse(dateString);

// Convert a Date to a String
String dateStringFromDate = sdf.format(dateFromDateString);

如果您需要的不仅仅是DateString 对象的简单转换,您可以使用DateFormat。这几乎是日期字符串转换的劳斯莱斯。它可以以更通用的方式解析和格式化字符串,而实际上不需要模式,它会自动考虑语言环境等等。

或者你可以使用JodaTime :)

【讨论】:

  • 你为什么将字段声明为 final?
  • 我将这些字段声明为最终字段,因为我不希望它们发生变化。分配一次后,您不能将值分配给最终字段,此外,您必须在静态上下文或构造函数中分配值。通常,对于此代码,它并没有太大的区别,但对于更复杂的代码,将字段标记为 final 可能会有很大帮助。一方面是因为您可以确定该字段已被分配了一个值,并且您可以确定没有人可以更改该值。
  • 我知道final是什么意思,但是我没看懂这里的逻辑,因为假期不止一个。
  • 那么 final 与多个实例无关。每个实例仍然有其 one 值。
【解决方案2】:

我认为问题在于在这部分代码中转换为 int: return (int) calendar.getTimeInMillis();

calendar.getTimeInMillis() 返回 long,转换为 int 会导致问题。

【讨论】:

    【解决方案3】:

    tl;博士

    holidays.add( 
        new Holiday( 
            LocalDate.of( 2018 , Month.MAY , 8 ) , 
            "National Coconut Cream Pie Day" 
        ) 
    )
    

    java.time

    使用现代的 java.time 类而不是过时的遗留 Calendar 类及其常用的子类 GregorianCalendar,这项工作要简单得多。

    LocalDate

    LocalDate 类表示没有时间和时区的仅日期值。

    时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

    如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。

    continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

    ZoneId z = ZoneId.of( "America/Montreal" ) ;  
    LocalDate today = LocalDate.now( z ) ;
    

    如果你想使用 JVM 当前的默认时区,请求它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的,因为默认值可能会在任何时候在运行时被 JVM 中任何应用程序的任何线程中的任何代码更改。

    ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.
    

    或者指定一个日期。您可以通过数字设置月份,1 月至 12 月的编号为 1-12。

    LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ;  // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
    

    或者,更好的是,使用预定义的Month 枚举对象,一年中的每个月一个。提示:在整个代码库中使用这些 Month 对象,而不是仅仅使用整数,以使您的代码更具自记录性,确保有效值,并提供 type-safety

    LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
    

    自定义类

    您在代码中两次误用了名称 Holidays,一次是列表集合的名称,一次是单个“假期”类/对象的名称。此外,第一个用作保存静态类的变量,不太可能是一个好的设计。

    我假设第二个是错字,第二个应该是 Holiday 作为代表特定日期的特定假期的类的名称。

    你的Holiday 类看起来像这样。

    class Holiday
    {
        private LocalDate localDate;
        private String name;
        private DayOfWeek dow;
    
        public Holiday ( LocalDate localDateArg , String nameArg )
        {
            this.localDate = localDateArg;
            this.name = nameArg;
        }
    
        public LocalDate getLocalDate ( )
        {
            return localDate;
        }
    
        public String getName ( )
        {
            return name;
        }
    
        // With arguments.
        public String format ( Locale locale , FormatStyle style )
        {
            String date = this.localDate.format( DateTimeFormatter.ofLocalizedDate( style ).withLocale( locale ) );
            String output = date + " | " + this.name;
            return output;
        }
    
        @Override
        public String toString ( )
        {
            return "Holiday{ " +
                    "localDate=" + localDate +
                    ", name='" + name + '\'' +
                    " }";
        }
    }
    

    接下来,我们使用那个类。

    List

    实例化一个空的List。您可以选择设置ArrayList 的初始容量。

    List < Holiday > holidays = new ArrayList <>( 3 );
    

    填充该列表。

    holidays.add( new Holiday( LocalDate.of( 2018 , Month.MAY , 8 ) , "National Coconut Cream Pie Day" ) );
    holidays.add( new Holiday( LocalDate.of( 2018 , Month.AUGUST , 9 ) , "National Rice Pudding Day" ) );
    holidays.add( new Holiday( LocalDate.of( 2018 , Month.JANUARY , 5 ) , "National Whipped Cream Day" ) );
    

    holidays.toString():

    [Holiday{ localDate=2018-05-08, name='全国椰子奶油派日'}, Holiday{ localDate=2018-08-09, name='全国大米布丁日'}, Holiday{ localDate=2018 -01-05,name='全国鲜奶油日'}]

    Comparator排序

    要排序,请传递Comparator 的实现。这是经典的 Java 语法。

    holidays.sort( new Comparator < Holiday >()
    {
        @Override
        public int compare ( Holiday o1 , Holiday o2 )
        {
            int c = o1.getLocalDate().compareTo( o2.getLocalDate() );
            return c;
        }
    } );
    

    这是使用 lambda 的现代 Java 语法中相同的 Comparator

    holidays.sort( ( o1 , o2 ) ->
    {
        int c = o1.getLocalDate().compareTo( o2.getLocalDate() );
        return c;
    } );
    

    甚至更短的 lambda 语法,但不一定更好。

    holidays.sort( ( o1 , o2 ) -> o1.getLocalDate().compareTo( o2.getLocalDate() ) );
    

    无论哪种方式,结果都是:

    holidays.toString():

    [Holiday{ localDate=2018-01-05, name='National Whipped Cream Day' }, Holiday{ localDate=2018-05-08, name='National Coconut Cream Pie Day'}, Holiday{ localDate=2018 -08-09, name='全国大米布丁日'}]

    格式化输出

    对于带有星期几的日期,请使用我们定义的 format 方法,该方法会自动本地化为我们通过 LocaleFormatStyle 指定的人类语言和文化规范。

    for ( Holiday holiday : holidays )
    {
        System.out.println( holiday.format( Locale.CANADA_FRENCH , FormatStyle.FULL ) );
    }
    

    vendredi 2018 年 1 月 5 日 |全国鲜奶油日

    狂欢节 2018 年 5 月 8 日 |全国椰子奶油派日

    jeudi 9 août 2018 |全国大米布丁日

    或者美国英语,通过Locale.US:

    2018 年 1 月 5 日,星期五 |全国鲜奶油日

    2018 年 5 月 8 日,星期二 |全国椰子奶油派日

    2018 年 8 月 9 日,星期四 |全国大米布丁日

    请注意,您可以从LocalDate 获取DayOfWeek 枚举对象。从此,您可以使用 DayOfWeek::getDisplayName 方法自动本地化当天的名称。


    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

    您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

      猜你喜欢
      • 2019-11-15
      • 2020-02-05
      • 2018-05-15
      • 1970-01-01
      • 2019-05-25
      • 2019-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多