[英]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
使用LocalDate
,從不使用Calendar
。
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
.with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) )
.plusDays( i ) )
避免使用麻煩的舊遺留類Calendar
因為它現在已經遺留下來,取而代之的是java.time類(特別是ZonedDateTime
)。
對於沒有時間的僅限日期的值,請使用LocalDate
而不是日期+時間類型,如Calendar
或ZonedDateTime
。 LocalDate
類表示沒有時間且沒有時區的僅日期值。
時區對於確定日期至關重要。 對於任何給定的時刻,日期在全球范圍內因地區而異。 例如, 法國巴黎午夜過后幾分鍾是新的一天,而在魁北克蒙特利爾仍然是“昨天”。
如果未指定時區,則JVM會隱式應用其當前的默認時區 。 該默認值可能隨時更改,因此您的結果可能會有所不同。 最好明確指定您期望/預期的時區作為參數。
以continent/region
的格式指定適當的時區名稱 ,例如America/Montreal
, Africa/Casablanca
或Pacific/Auckland
。 切勿使用3-4字母縮寫,例如EST
或IST
因為它們不是真正的時區,不是標准化的,甚至不是唯一的(!)。
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 8及更高版本中。 這些類取代了麻煩的舊遺留日期時間類,如java.util.Date
, Calendar
和SimpleDateFormat
。
現在處於維護模式的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的試驗場。 您可以在這里找到一些有用的類,比如Interval
, YearWeek
, YearQuarter
,和更多 。
更新: 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.