Java日历每周星期几不正确

时间:2019-07-26 13:09:05

标签: java android

我目前正在开发需要处理日期,时间等信息的应用程序。我遇到了一个非常简单的问题:从给定日期(以毫秒为单位)获取一周中的正确日期。 我确定,知道当前日期的给定时间(以毫秒为单位)是正确的时间,问题在于_calendar变量返回的日期是给定时间的一天之后。

我尝试使用Java中的DateFormat或其他日期处理类,但是我当前用于Android应用的最小API是22。

private void getDayOfTheWeek(Long dateInMillis) {
    Date _date = new Date();
    _date.setTime(dateInMillis);
    Calendar _calendar = Calendar.getInstance();
    _calendar.setTime(_date);
    mDayOfTheWeek = mDaysOfTheWeek[_calendar.get(Calendar.DAY_OF_WEEK) - 1];
    Log.d("FirebaseDay", mDayOfTheWeek + "; " + _calendar.getTimeInMillis());
}

例如,对于日期: 1564088400000 它应该返回:5,即星期五,尽管 _calendar.getTimeInMillis()与给定的相同

编辑:问题不在于它返回一个数字,我有一个字符串数组,mDaysOfTheWeek使我从_calendar接收到整数之后的第二天。结果是6。

private final String[] mDaysOfTheWeek
        = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; 

3 个答案:

答案 0 :(得分:1)

tl; dr

  

它应该返回:5,即星期五,…6是返回的结果。

可怕的Calendar类有很多问题。

  • 一个问题是,它根据JVM当前的默认语言环境隐式地使用转移行为。当您的代码在设置为美国区域设置的JVM上运行时,您将发现星期四是星期日至星期六的一周中的另一天,而不是欧洲或一周中星期一至星期日的其他地方。
  • 另一个问题是疯狂的从零开始的计数,一周中的几天为0-6,几个月为0-11。

改为使用 java.time 。计数是理智的(周一至周日为1-7),并且可以使时区行为可预测和明确。

重要:时区至关重要。对于更东部的地区,您的时刻显示为星期五。对于其他西部地区,您的时刻显示为星期四。

Instant                            // Represent a moment in UTC.
.ofEpochMilli(                     // Parse your count-from-epoch 1970-01-01T00:00:00Z.
    1_564_088_400_000L             // Use underscores where you like, to make numeric literals more readable.
)                                  // Returns an `Instant` object.
.atZone(                           // Adjust from UTC to some time zone.
    ZoneId.of( "Asia/Tokyo" )      // Specify time zone using `Continent/Region` format, never 2-4 letter pseudo-zones such as `EST` or `CST` or `IST`. 
)                                  // Returns a `ZonedDateTime` object.
.getDayOfWeek()                    // Returns a `DayOfWeek` object.
.getDisplayName(                   // Generate automatically-localized string for the name of the day-of-week.
    TextStyle.FULL ,               // How long or abbreviated.
    Locale.US                      // Locale determines (a) human language for translation, and (b) cultural norms for issues such as abbreviation, punctuation, capitalization.
)                                  // Returns a `String`.

请参阅此code run live at IdeOne.com

  

星期五

如果您坚持在周一至周日使用1-7,请致电getValue而不是.getDisplayName

.getValue()
  

5

避免使用旧的日期时间类

  

我目前正在开发需要处理日期,时间等信息的应用程序。

然后,您应该停止使用在几年前被JSR 310淘汰的可怕的日期时间类。仅使用现代的 java.time 类。切勿使用DateCalendar

从纪元开始计数

  

从给定日期开始(以毫秒为单位)。

如果您指的是自UTC 1970年第一时刻的纪元参考以来的毫秒数,请解析为InstantInstant代表UTC的时刻,即时间轴上的特定点。

Instant instant = Instant.ofEpochMilli( 1_564_088_400_000L ) ;

请参阅此代码在IdeOne.com上实时运行。

  

instant.toString():2019-07-25T21:00:00Z

日期

  

获取正确的星期几

从某个时刻确定日期需要时区的上下文。在任何给定的时刻,日期都会在全球范围内变化。在法国巴黎,日期可以同时是“明天”,而在蒙特利尔魁北克省则可以是“昨天”。

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

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

要在时区中调整时间,请将ZoneId应用于Instant以获得ZonedDateTime

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

如果要通过UTC而不是其他时区查看日期,请使用OffsetDateTime类。

ZoneOffset offset = ZoneOffset.UTC ;  // Constant for UTC (an offset of zero hours-minutes-seconds). 
OffsetDateTime odt = instant.atOffset( offset ) ;

如果您想走这条路线(UTC),请用下面的zdt替换下面代码中的odt

星期几

使用DayOfWeek枚举查询一周中的某天。

DayOfWeek dow = zdt.getDayOfWeek() ;
  

或示例,日期:1564088400000它应返回:5,

不,我建议您使用智能对象,而不要使用哑整数。与其使用5来表示Friday(顺便说一句,在美国将意味着Thursday),而是在代码库中传递DayOfWeek枚举对象。

要报告要使用的星期几,请进行本地化。

String output = dow.getDisplayName( TextStyle.FULL , Locale.CANADA_FRENCH ) ;

或者,如果您坚持要使用的话,则在周一至周日使用1到7的ISO 8601编号方案生成数字。

int dayOfWeekNumber = dow.getValue() ; 
  

private final String [] mDaysOfTheWeek = {“星期一”,“星期二”,“星期三”,“星期四”,“星期五”,“星期六”,“星期日”};

无需自己动手。使用DayOfWeek枚举。


关于 java.time

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

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

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

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

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:0)

如果您观看Calendar

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Sunday.
 */
public final static int SUNDAY = 1;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Monday.
 */
public final static int MONDAY = 2;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Tuesday.
 */
public final static int TUESDAY = 3;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Wednesday.
 */
public final static int WEDNESDAY = 4;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Thursday.
 */
public final static int THURSDAY = 5;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Friday.
 */
public final static int FRIDAY = 6;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Saturday.
 */
public final static int SATURDAY = 7;

因此, 1564088400000 的星期几返回6(public final static int FRIDAY = 6;)。 5.您mDaysOfTheWeek中的索引(6-1-1)是星期六

答案 2 :(得分:0)

正如预期的那样,它将返回6,即星期五。但是您设置的mDaysOfTheWeek字符串数组设置错误。

参考:

来自类 Calendar.java

public final static int SUNDAY = 1;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Monday.
 */
public final static int MONDAY = 2;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Tuesday.
 */
public final static int TUESDAY = 3;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Wednesday.
 */
public final static int WEDNESDAY = 4;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Thursday.
 */
public final static int THURSDAY = 5;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Friday.
 */
public final static int FRIDAY = 6;

/**
 * Value of the {@link #DAY_OF_WEEK} field indicating
 * Saturday.
 */
public final static int SATURDAY = 7;