繁体   English   中英

Java日历每周星期几不正确

[英]Java Calendar doesn't get correct day of the week

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

我尝试使用DateFormat或Java的其他日期处理类,但是当前用于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接收到整数后的_calendar 结果为6。

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

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`.

看到此代码在IdeOne.com上实时运行

星期五

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

.getValue()

5

避免使用旧的日期时间类

我目前正在开发需要与日期,时间等配合使用的应用程序。

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

从时代开始计数

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

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

Instant instant = Instant.ofEpochMilli( 1_564_088_400_000L ) ;

看到此代码在IdeOne.com上实时运行。

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

日期

得到正确的一周中的一天

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

Continent/Region的格式指定正确的时区名称 ,例如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() ; 

私有最终String [] mDaysOfTheWeek = {“星期一”,“星期二”,“星期三”,“星期四”,“星期五”,“星期六”,“星期日”};

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


关于java.time

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

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

现在处于维护模式Joda-Time项目建议迁移到java.time类。

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

在哪里获取java.time类?

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

如果看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.您的mDaysOfTheWeekSaturday

正如预期的那样,它将返回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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM