当前位置: 首页 > 知识库问答 >
问题:

Java 和多 SQL RDBMS 之间的一年中的一周计算差异

邓浩漫
2023-03-14

我必须做一些报告,必须用Java和MySQL计算任意日期的星期,但是它们有不同的算法

首先,请注意,根据某些方法,某年年末的某几天是下一年的第一周。示例:2012-12-31是2013年的第一周(我不记得具体年份,但大概是这样)。所以我必须计算出一个日期中正确的星期和年份

在Java中,它基于两个取决于语言环境的标准:

>

  • 一周的第一天(星期日或星期一)
  • 第一周最少天数(1或4天)

    Calendar cal = Calendar.getInstance();
    int javaWeek = cal.get(Calendar.WEEK_OF_YEAR);
    int weekYear = cal.getWeekYear();
    

    在 MySQL 中,它基于 2 个标准,具体取决于模式(0 到 7):

    > < li >一周的第一天(星期日或星期一)(在Java中也是如此)

  • < li>

    第一周的最小天数为4天,或者第一周包含一周的第一天

    SELECT WEEK('2012-12-12', 1);
    SELECT YEARWEEK('2012-12-12', 1);
    

    而在 MySQL 中,一些模式会用奇怪的结果计算一周,例如,一年有第 0 周只有 1 天,而其他周有整整 7 天(我认为第 1 周实际上是第一周,而第 0 周是前周什么的)。我会忽略这些模式

    场景是:我在 Java 中根据我的系统区域设置(设置为:getFirstDayOfWeek()==SUNDAYgetMinimalDaysInFirstWeek==1)计算日期列表的一周,我想在 MySQL 中计算相同的结果

    但我尝试了MySQL中的所有8模式,没有一个匹配。我失败了,因为在MySQL中没有模式calc week based on minimal day in first week is 1(只有一些模式带有4),所以我手动<code>setMinimalDaysInFirst week(4)</code>,MySQL中的模式6与Java中的结果相匹配

    (我必须写一个测试,比较2年来Java和MySQL中每天的结果)

    所以我的解决方案是,我必须修复< code > setMinimalDaysInFirstWeek(4),如果< code>getFirstDayOfWeek()是星期一,我在MySQL中选择模式3,如果< code>getFirstDayOfWeek()是星期天,我在MySQL中选择模式6。我认为这只是一个临时的解决方案,而且真的很奇怪。

    还有一个问题,我真的很担心如果我的系统从MySQL更改为其他RDBMS,它会有其他方法,我无法处理所有这些方法(Oracle中的示例没有WEEK功能)。那么,有什么方法可以计算满足许多RDBMS的周数吗?

    我有一个想法是在一个平台(Java或MySQL)上计算周,然后将结果传递给另一个平台:

    >

  • 如果从Java传递到MySQL,我已经将结果传递给查询字符串,或者构建一个包含我结果的表

    如果从MySQL传递到Java,我必须编写一个从Java调用它的过程,并且必须解决“找到计算周满足许多RDBMS的方法”的问题

    但是我必须计算大量的日期,这些都不让我满意,有人有想法解决我的问题吗?

  • 共有1个答案

    微生嘉
    2023-03-14

    虽然我在工作周方面没有太多经验,但在我看来,最明智的方法是遵循ISO 8601标准。该标准清楚地定义了星期和星期的数字。

    标准说:

    • 星期一开始
    • 一周中的天数从17。周一=1.
    • 第一周包含一年中的第一个星期四
    • 周编号为0153。(无00。)

    虽然我不知道MySQL(我是一个Postgres类型的人),但我确实读了这个关于日期和时间函数的留档。

    WEEK(日期,模式函数的模式3似乎符合ISO 8601,其中一周的第一天是星期一,周编号为1-53,今年有4天或更多天(不是官方定义,而是另一种说法“包含第一个星期四”)。

    此外,MySQL提供了WEEKOFYEAR(date)函数,专门作为使用模式3调用WEEK的简写。所以我建议你坚持调用WEEKOFYEAR。

    时区至关重要。日期由时区决定。尽管蒙特利尔正在享受2012年12月12日星期三晚上午夜前的最后时刻,但在巴黎,星期四已经到来,日期是13日。宇宙历史上的同一时刻,但日期和时间不同。

    我假设但不知道MySQL以UTC存储日期时间值。所以我也假设调用它们与星期相关的函数在UTC中有效地工作,不应用任何时区调整。

    我怀疑这可能是你问题的根源。如果您忘记指定一个时区,java.util.Calendar类会指定JVM的默认时区。顺便说一下,这是一个重要的教训:总是指定一个时区,而不是依赖隐式默认。所以MySQL是用UTC计算一年中的星期,而Calendar是用其他时区(巴黎,加尔各答,等等)计算的,显然结果会不同。

    我的猜测是,解决方案是:

    • 使用UTC始终如一地完成Java工作
    • 在MySQL中对您的日期时间值应用时区调整(如果可能,我不知道)。

    哪种解决方案最好取决于您的业务策略。一些企业可能希望按照其总部或主要供应商/客户等的时区工作。其他企业,尤其是那些关注不同时区的企业,选择用UTC来定义一切。

    我怀疑,从长远来看,在这个世界日益缩小的时代,大多数人最明智的选择是始终在UTC工作。但我不是经营你公司的人。

    至于Java方面的事情,避免使用java.util.Date。

    许多java.time功能已反向移植到Java6

    请参阅 Oracle 教程 java.time 主题。

    看到我对类似问题的回答。

    表示时间轴上的一个点,分辨率为纳秒,调整为 UTC 偏移量(不是完整时区)。

    OffsetDateTime twelves = OffsetDateTime.of( 2012, 12, 12, 0, 0, 0, 0, ZoneOffset.UTC );
    

    OffsetDateTime::get方法允许您访问值的任何部分。每个部分都定义为TemporalFieldIsoFields类提供了特定于ISO-8601日历系统TemporalField的实现。这包括我们需要的两个:

    • IsoFields.WEEK_OF_WEEK_BASED_YEAR
    • IsoFields.WEEK_BASED_YEAR

    在使用中…

    int week = twelves.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
    int weekYear = twelves.get ( IsoFields.WEEK_BASED_YEAR );
    

    时区是UTC的偏移量加上一组处理异常情况的规则,如夏令时(DST)。在某些时区,一天不是从00:00:00.0开始的。因此,我们通过LocalDate类(仅限日期的值)让java.time确定一天的第一个时刻。

    ZoneId zoneId = ZoneId.of( "America/Montreal" );
    LocalDate twelves = LocalDate.of( 2012 , 12 , 12 );
    ZonedDateTime twelvesMontreal = twelves.atStartOfDay( zoneId );
    int week = twelvesMontreal.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
    int weekYear = twelvesMontreal.get ( IsoFields.WEEK_BASED_YEAR );
    

    如果你确定时间和时区是不相关的(三思而后行!),那么您可以单独使用< code>LocalDate,因为它也有一个< code>get方法。

    LocalDate twelves = LocalDate.of( 2012 , 12 , 12 );
    int week = twelves.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
    int weekYear = twelves.get ( IsoFields.WEEK_BASED_YEAR );
    

    方法getWeekOfWeekYear获取周数。ISODateTimeFormat类具有工厂方法,用于为ISO 8601定义的各种与周相关的格式生成格式化程序。

    DateTime twelves = new DateTime( 2012, 12, 12, 0, 0, 0, DateTimeZone.UTC );
    int weekOfTwelves = twelves.getWeekOfWeekyear();
    

    创建字符串表示。请注意,如果您希望格式化程序对其字符串生成应用时区调整,则可以使用zone追加对的调用。否则,将使用DateTime分配的时区。

    String outputWeek = ISODateTimeFormat.weekyearWeek().print(  twelves );
    String outputWeekDate = ISODateTimeFormat.weekDate().print(  twelves );
    

    转储到控制台。

    System.out.println( "twelves: " + twelves );
    System.out.println( "weekOfTwelves: " + weekOfTwelves );
    System.out.println( "outputWeek: " + outputWeek );
    System.out.println( "outputWeekDate: " + outputWeekDate );
    

    运行时。

    twelves: 2012-12-12T00:00:00.000Z
    weekOfTwelves: 50
    outputWeek: 2012-W50
    outputWeekDate: 2012-W50-3
    

    至于移植到MySQL以外的数据库,我认为坚持越来越普遍的ISO 8601标准将有助于提高可移植性。

    例如,Postgres提供了函数< code>isoyear 、< code>week和< code>isodow(星期几),这些函数都符合ISO 8601标准。

     类似资料:
    • 问题内容: Java 8的类有一个方法,,它使您可以从字符串A-z,a-z字母定义格式。这些例子并没有明确的区别y,今年的时代和Y,以星期为一年。它是什么? 问题答案: 与2006-W52一样,这是“年-周”样式日期的年值。如果有问题的一周跨越年份边界,则可能偏离年份值+1或-1。

    • 本文向大家介绍怎么实现一个计算一年中有多少周?相关面试题,主要包含被问及怎么实现一个计算一年中有多少周?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 首先你得知道是不是闰年,也就是一年是365还是366. 其次你得知道当年1月1号是周几。假如是周五,一年365天把1号 2号3号减去,也就是把第一个不到一周的天数减去等于362  

    • 问题内容: 问题 我仍在用SQL寻找自己的脚,并尝试计算某个用户在轮班期间扫描项目多长时间。 每次扫描都带有时间戳,生成唯一的9位数序列号( SEQ 列)和格式( THE_DATE 列)的日期/时间。 这个人可能正在扫描几个小时,我想做的是从轮班结束时的最后一个时间戳减去他们生成的第一个时间戳。 因此,例如,给出此数据样本: 期望的结果 我想从出现的最后一行减去Mike Derry的第一行的时间戳

    • 问题内容: 我正在尝试编写一种方法来打印两个 ZonedDateTime 之间的 时差 ,关于时区之间的时差。 我找到了一些解决方案,但所有解决方案均编写为可与 LocalDateTime一起使用 。 问题答案: 您可以使用方法 之间 的 ChronoUnit 。 此方法将那些时间转换为相同的区域(第一个参数的区域),然后,调用 直到 在 Temporal 接口中声明的方法 为止 : 由于 Zon

    • 问题内容: 我试图计算两者之间的差异。 输出必须为格式。这是我写的: 我得到的输出是。我已经从该网站检查了我的结果(带有)。以下屏幕截图显示了输出: 我很确定月份值后面的字段在我的代码中出了错。任何建议都将非常有帮助。 更新资料 我已经从另一个网站测试了我的结果,但是得到的结果却有所不同。在这里是:计算两个日期之间的持续时间(结果:29年,8个月,24天,12小时,0分钟和50秒)。 更新资料 由

    • 问题内容: 我有一个带有StartDate列的表,我想计算两个连续记录之间的时间差。 谢谢。 @ Mark Byers和@ Yahia,我将请求表作为requestId,startdate 我想知道requestid 1和2、2和3、3和4等之间的时差是多少。我知道我需要在表上进行自我连接,但是我在子句上没有得到正确的支持。 问题答案: 要实现您的要求,请尝试以下操作(从OP编辑后进行更新): 如

    • 本文向大家介绍PHP计算一年多少个星期和每周的开始和结束日期,包括了PHP计算一年多少个星期和每周的开始和结束日期的使用技巧和注意事项,需要的朋友参考一下 项目中需要做个提交周报的功能,需要知道指定周数的开始日期和结束日期,以便处理其他业务。以下是一段通过PHP来获取一年中的每星期的开始日期和结束日期的代码,与大家分享。 函数get_week()通过传入参数$year年份,获取当年第一天和最后一天

    • 问题内容: 请包括nanos,否则将是无关紧要的: [编辑]我想要最精确的结果,所以不要双打;仅整数/长算术。同样,结果必须是肯定的。伪代码: 例子: 是的,在java.sql.Timestamp中毫秒被复制的时间和毫微秒不相上下,所以1001个毫秒装置1秒(1000)和1毫这是在部件和部分,因为1毫秒= 1000000毫微秒)。这比看起来要狡猾得多。 我建议不要在未实际测试代码或未准备好工作代码