android 如何识别一周中的同一天

android how to identify the same days of a week

为了管理日期,我使用了 class 日历。我在数据库中保存时间戳,使用

日历时间戳=Calendar.getInstance();

我能够使用长值存储日期来保存和检索数据库中的日期。

这是我的问题:当我要存储时间戳时,我需要知道数据库中是否已经存在属于同一周的时间戳。为此,我想我可以使用以下两种方法:

timestamp.get(Calendar.YEAR)timestamp.get(Calendar.WEEK_OF_YEAR)

唯一标识一个星期,但对于具有属于连续两年的日子的星期则不是这样。

这是我在 2014 年最后一周得到的示例。

2014 年 12 月 27 日,星期六 年份:2014 周:52

2014 年 12 月 28 日,星期日 年份:2014 周:1

2014 年 12 月 29 日,星期一 年份:2014 周:1

2014 年 12 月 30 日,星期二 年份:2014 周:1

2014 年 12 月 31 日,星期三 年份:2014 周:1

2015 年 1 月 1 日,星期四 年份:2015 周:1

2015 年 1 月 2 日,星期五 年份:2015 周:1

2015 年 1 月 3 日,星期六 年份:2015 周:1

2015 年 1 月 4 日,星期日 年份:2015 周:2

从 28/12/2014 到 3/1/2015 这几天属于同一周(在 java 中,该周从星期日开始),但他们的年份不同,所以这对夫妇 (YEAR , WEEK_OF_YEAR) 没有给我他们属于同一周的信息。

我该如何解决?

要获取相对于日期的一周的第一天和最后一天,请执行以下操作:

Calendar cal = Calendar.getInstance();
cal.setTime(date); // date to check
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
Date startOfWeek = cal.getTime();
cal.add(Calendar.DAY_OF_MONTH, 6);
Date endOfWeek = cal.getTime();

免责声明: 我从 How to get the first day of the current week and month?

那里偷了一部分

然后使用检查日期范围的 where 子句。

SELECT * FROM mytable WHERE mydate >= ? AND mydate <= ?

如果您存储的日期包括时间,您希望通过添加 7 而不是 [=17] 作为 上限 边界=] 天以上。

SELECT * FROM mytable WHERE mydate >= ? AND mydate < ?

为了显示日期逻辑,这里有一些测试代码:

// Start on 12/27/2014
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(2014, Calendar.DECEMBER, 27);

// Collect 10 dates to test (start date + next 9 days)
Date[] dates = new Date[10];
dates[0] = cal.getTime();
for (int i = 1; i < dates.length; i++) {
    cal.add(Calendar.DAY_OF_MONTH, 1);
    dates[i] = cal.getTime();
}

// Test loop    
SimpleDateFormat fmt = new SimpleDateFormat("EEE d/M/yyyy");
for (Date date : dates) {

    // Code to test
    cal.setTime(date);
    cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
    Date startOfWeek = cal.getTime();
    cal.add(Calendar.DAY_OF_MONTH, 6);
    Date endOfWeek = cal.getTime();

    // Show result
    System.out.println(fmt.format(date) + "  ->  " + fmt.format(startOfWeek) +
                                             " - " + fmt.format(endOfWeek));
}

输出

Sat 27/12/2014  ->  Sun 21/12/2014 - Sat 27/12/2014
Sun 28/12/2014  ->  Sun 28/12/2014 - Sat 3/1/2015
Mon 29/12/2014  ->  Sun 28/12/2014 - Sat 3/1/2015
Tue 30/12/2014  ->  Sun 28/12/2014 - Sat 3/1/2015
Wed 31/12/2014  ->  Sun 28/12/2014 - Sat 3/1/2015
Thu 1/1/2015  ->  Sun 28/12/2014 - Sat 3/1/2015
Fri 2/1/2015  ->  Sun 28/12/2014 - Sat 3/1/2015
Sat 3/1/2015  ->  Sun 28/12/2014 - Sat 3/1/2015
Sun 4/1/2015  ->  Sun 4/1/2015 - Sat 10/1/2015
Mon 5/1/2015  ->  Sun 4/1/2015 - Sat 10/1/2015

按照@basil 的建议,我尝试了 Joda-Time 库,并在那里找到了解决我的问题的方法。 要获得一年中的第几周,我可以使用 getWeekOfWeekyear() 方法,要获得年份,我可以使用方法 getWeekyear()

这样,这对值就唯一标识属于同一周的一天,一周从星期一开始到星期日结束(相对于Java日历class).

按照问题的相同示例。

DateTime[] timestamp = new DateTime[10];

for(int i=0; i<10; i++){
   //set the start of the period
   DateTime time = new DateTime(2014, 12, 27, 18, 30, 50);
   //add i days to the start date
   timestamp[i] = time.plus(Period.days(i));

   int weekYear = timestamp[i].getWeekyear();
   int weekOfWeekyear = timestamp[i].getWeekOfWeekyear();

   Log.d(Constants.LOG_TAG, timestamp[i].toString("EEEE, MMMM d, yyyy") + " | year.week = " + weekYear + "." + weekOfWeekyear);
}

结果是:

2014 年 12 月 27 日,星期六 | year.week = 2014.52

2014 年 12 月 28 日,星期日 | year.week = 2014.52

2014 年 12 月 29 日,星期一 | year.week = 2015.1

2014 年 12 月 30 日,星期二 | year.week = 2015.1

2014 年 12 月 31 日,星期三 | year.week = 2015.1

2015 年 1 月 1 日,星期四 | year.week = 2015.1

2015 年 1 月 3 日,星期六 | year.week = 2015.1

2015 年 1 月 4 日,星期日 | year.week = 2015.1

2015 年 1 月 5 日,星期一 | year.week = 2015.2

看起来使用这个库还有很多其他优点,它对我必须执行的其他计算很有用。

谢谢@basil。

tl;博士

你必须明白“正常”的区别calendar year and a standard week-based year。日历年的 first/last 几天可能出现在 previous/next week-based 年。

2014 日历年当然是在 2014 年 12 月 31 日结束。但是 2014 年的最后一天是 下一个 week-based 年,2015 年。

week-based 2014 年的最后一天于 2014 年 12 月 28 日(日历年)结束。 2015 week-based 年的第一天是 2014 年 12 月 29 日(日历年)。上面的日历图应该清楚这些事实。

2014-12-28 = 2014-W52-7

2014-12-29 = 2015-W01-1

2015-01-01 = 2015-W01-4

询问 week-based 周数和年数:

myZonedDateTime.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )

……和……

myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR )

简单地说:对于一年中的 last/first 几天,调用 myZonedDateTime.getYear()myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR ) 的结果可能会有所不同.

java.time

现代方法使用 java.time classes 取代了麻烦的旧遗留 date-time classes。

To manage dates I'm using the class Calendar. I'm saving timestamps in a DB, using Calendar timestamp = Calendar.getInstance();

相反,使用ZoneDateTime捕捉当前时刻,用wall-clock某个地区(时区)的人使用的时间。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

I'm able to save and retrieve the dates from the DB using long values to store dates.

不,在定义数据库列和 Java 代码时使用适当的数据类型。

要在符合 SQL 标准的数据库中存储时间轴上的特定时刻,请将您的列定义为 TIMESTAMP WITH TIME ZONE

使用 JDBC 4.2 及更高版本,您可以直接与数据库交换 java.time 对象。

myPreparedStatement.setObject( … , zdt ) ;

检索为 Instant,UTC 时刻,可能是另一个方向的最佳路线。然后调整到您想要的时区。

Instant instant = myResultSet.getObject( … , Instant.class ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

This is my problem: when I have a timestamp to store, I need to know if in the DB there is already a timestamp belonging to the same week. To do this I thought I could use the couple of methods: timestamp.get(Calendar.YEAR) and timestamp.get(Calendar.WEEK_OF_YEAR)

不幸的是,在令人困惑的 Calendar class 中,一周的含义因地区而异。

也许您自己的定义符合标准ISO 8601 definition of a week

  • 第一天是星期一,运行 到星期日。
  • week-based 年的第一个星期包含日历年的第一个星期四。
  • week-based 年有 52 周或 53 周。
  • 一个日历年的 first/last 几天可能出现在 previous/next week-based 年。

请注意,确定星期需要确定日期。确定日期需要时区。对于任何给定时刻,日期在全球范围内因地区而异。因此,请清楚您对时区 (ZoneId) 的使用,如上所示。换句话说,周数是上下文相关的;这取决于特定区域的日期。

ZonedDateTime::get 中访问 TemporalFieldIsoFields class定义了你需要的常量。

int week = zdt.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int weekBasedYear = zdt.get( IsoFields.WEEK_BASED_YEAR ) ;

更好的是,添加 ThreeTen-Extra library to your project to use YearWeek class.

org.threeten.extra.YearWeek yw = YearWeek.from( zdt ) ;

to uniquely identify a week, but this isn't true for weeks having days belonging to two consecutive years.

This is an example of what I get for the last week of the year 2014.

Saturday, December 27, 2014 year: 2014 week: 52

在标准周中,2014-12-27 在第 52 周。

YearWeek.from( LocalDate.parse( "2014-12-27" )  ).toString()

2014-W52

2014 年底恰好在 下一个 week-based 年(2015 年)。

YearWeek.from( LocalDate.parse( "2014-12-31" ) ).toString()

2015-W01

可以比较YearWeek。调用 equalsisBeforeisAfter 方法。

boolean sameYearWeek = YearWeek.from( someZdt ).equals( YearWeek.from( otherZdt ) ) 

术语

因此,请确保在您的文档、代码注释和讨论中始终区分日历年和 week-based 年。永远不要说 "the year" 因为那是非常模棱两可的。

加上财政年度会更加混乱。还有一些行业有自己的年份、季节等定义。所以要小心你的条款。

注意日历软件设置

永远不要假设周数的定义。请确保此类数字的来源与您具有相同的周定义,例如 ISO 8601 定义。

例如 Calendar app supplied by Apple with macOS defaults to a "Gregorian" calendar definition of week. As for what that means, I do not know as I could not find any documentation as to their intent/definition. For ISO 8601 weeks, you must change a setting away from default.


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

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

从哪里获得java.time classes?

  • Java SE 8, Java SE 9,及以后
    • Built-in。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and Java SE 7
    • java.time 的大部分功能是 back-ported 到 Java ThreeTen-Backport 中的 6 和 7。
  • Android
    • Android java.time classes.
    • 捆绑实施的更高版本
    • 对于较早的 Android (<26),ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See .