簡體   English   中英

Android日歷問題與星期幾

[英]Android Calendar problem with day of the week

我想列出周一到周日當周的所有日子。 例如,今天(發布的那天)是2011年9月4日,也就是星期天。

我正在開始日歷並將一周的第一天設置為星期一:

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);

當我檢查每月的某天時,我得到了正確的結果:

int check = cal.get(Calendar.DAY_OF_MONTH);
// check is equal to 4

但是當我將工作日設置為星期一時,它會跳到下周,而不是在本周一返回:

cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
// mon is equal to 5, when expected to be 29 (last Monday of August)

即使設定工作日到周日也會在下周日返回,而不是今天。

有人可以解釋為什么它以這種方式工作,解決這個問題的最佳方法是什么?

事實上,當我檢查自己的測試時,它似乎按預期工作, 除非沒有再次設置日期

顯示4-29

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
cal.set(2011, 8, 4);
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon);

顯示5-5

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
cal.set(2011, 8, 5);
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon);

顯示14-12

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
cal.set(2011, 8, 14);
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon);

所以,這不起作用:

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);
//cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon); // Display 4-5

這工作

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);

// Workaround
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));

int test = cal.get(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + test + "-" + mon); // Display 4-29

也有效:

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);

// Workaround
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
cal.get(Calendar.DAY_OF_MONTH);

cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + mon); // Display 29

但是這個沒有:

Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.setMinimalDaysInFirstWeek(4);

// Workaround
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int mon = cal.get(Calendar.DAY_OF_MONTH);
bTest.setText("" + mon); // Display 5

TL;博士

使用LocalDate ,從不使用Calendar

LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
    .with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) )
    .plusDays( i ) )

java.time

避免使用麻煩的舊遺留類Calendar因為它現在已經遺留下來,取而代之的是java.time類(特別是ZonedDateTime )。

對於沒有時間的僅限日期的值,請使用LocalDate而不是日期+時間類型,如CalendarZonedDateTime LocalDate類表示沒有時間且沒有時區的僅日期值。

時區對於確定日期至關重要。 對於任何給定的時刻,日期在全球范圍內因地區而異。 例如, 法國巴黎午夜過后幾分鍾是新的一天,而在魁北克蒙特利爾仍然是“昨天”。

如果未指定時區,則JVM會隱式應用其當前的默認時區 該默認值可能隨時更改,因此您的結果可能會有所不同。 最好明確指定您期望/預期的時區作為參數。

continent/region的格式指定適當的時區名稱 ,例如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對象而不僅僅是整數,以使代碼更加自我記錄,確保有效值並提供類型安全性

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

DayOfWeek

對於星期幾,請使用DayOfWeek枚舉類。 它提供七個實例,一周中的每一天,周一至周日。

DayOfWeek dow = ld.getDayOfWeek() ;  // Get an enum representing the day-of-week of this date, such as `DayOfWeek.MONDAY`.

調整日期

我們需要找到上一個星期一,或者如果已經是星期一那么堅持今天的日期。 要移動到這樣的日期,使用TemporalAdjusters.previousOrSame實施TemporalAdjuster

TemporalAdjuster ta = TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) ;
LocalDate previousOrSameMonday = ld.with( ta ) ;

通過調用LocalDate.plusDays()來增加收集所需的日期。 請注意java.time如何使用不可變對象 我們根據原始值獲得一個新對象,而不是改變 (改變)原始對象。

// Hard-coded `7` is the seven days in a week.
List< LocalDate > dates = new ArrayList<>( 7 ) ;
for( int i = 0 , i < 7 , i ++ ) {
    LocalDate localDate = previousOrSameMonday.plusDays( i ) ;
    dates.add( localDate ) ;
}

關於java.time

java.time框架內置於Java 8及更高版本中。 這些類取代了麻煩的舊遺留日期時間類,如java.util.DateCalendarSimpleDateFormat

現在處於維護模式Joda-Time項目建議遷移到java.time類。

要了解更多信息,請參閱Oracle教程 並搜索Stack Overflow以獲取許多示例和解釋。 規范是JSR 310

您可以直接與數據庫交換java.time對象。 使用符合JDBC 4.2或更高版本的JDBC驅動程序 不需要字符串,不需要java.sql.*類。

從哪里獲取java.time類?

ThreeTen-Extra項目使用其他類擴展了java.time。 該項目是未來可能添加到java.time的試驗場。 您可以在這里找到一些有用的類,比如IntervalYearWeekYearQuarter ,和更多


更新: Joda-Time項目現在處於維護模式 ,團隊建議遷移到java.time類。 這部分留給了歷史。

喬達時間

什么是解決這個問題的最佳方法?

最好的方法是避免使用臭名昭着的java.util.Date和.Calendar類,而是使用Joda-Time庫。 Joda-Time適用於Android。

Joda-Time為沒有任何時間或時區的僅限日期值提供LocalDate類。

示例代碼

以下是使用Joda-Time 2.3的一些示例代碼。

LocalDate localDate = new LocalDate( 2011, DateTimeConstants.SEPTEMBER, 4 );
LocalDate firstDateOfWeek = localDate.withDayOfWeek( DateTimeConstants.MONDAY );
for ( int i = 0; i < 7; i++ ) {
    LocalDate someDateOfWeek = firstDateOfWeek.plusDays( i );
    System.out.println( "someDateOfWeek: " + someDateOfWeek + "  le jour de la semaine: " + someDateOfWeek.dayOfWeek().getAsText( Locale.CANADA_FRENCH ) );
}

跑的時候......

someDateOfWeek: 2011-08-29  le jour de la semaine: lundi
someDateOfWeek: 2011-08-30  le jour de la semaine: mardi
someDateOfWeek: 2011-08-31  le jour de la semaine: mercredi
someDateOfWeek: 2011-09-01  le jour de la semaine: jeudi
someDateOfWeek: 2011-09-02  le jour de la semaine: vendredi
someDateOfWeek: 2011-09-03  le jour de la semaine: samedi
someDateOfWeek: 2011-09-04  le jour de la semaine: dimanche

周數

額外提示:如果您想要ISO 8601標准定義的周數,請調用weekOfWeekYear方法。 像這樣:

int weekNumber = firstDateOfWeek.getWeekOfWeekyear();

你的約會對象是在第35周。

人類不能使用Android生物的語言,只是開玩笑,日期進入,是另一個釘入java棺材。 這個誤解問題的核心是糟糕的文件和兩個事實,月份從0開始,年份從1900開始,但不在日歷和他的后代中。 還有一個事實,在Date Sunday是0,但在Calendar Sunday是1。

//THIS WORKS CORRECTLY
Date my = new Date(1986 - 1900, 04 - 1, 26);
System.out.println(my);
System.out.println(my.getDay());

Calendar cal = Calendar.getInstance(TimeZone.getDefault());
cal.set(1986, 04 - 1, 26);
System.out.println(cal.getTime());
System.out.println(cal.get(Calendar.DAY_OF_WEEK)-Calendar.SUNDAY);

另一個,更方便的方式

//ONE AND ONLY, HUMAN FRIENDLY WAY TO ENTER DATE INTO JAVA
String date = "1986-04-26:01:23:47";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd:HH:mm:SS");
Date convertedDate = (Date) formatter.parse(date);
System.out.println(convertedDate);

很簡單,不是嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM