JodaTime或Java 8是否有特殊支持JD Edwards日期和时间? [英] Does JodaTime or Java 8 have special support JD Edwards Date and Time?

查看:200
本文介绍了JodaTime或Java 8是否有特殊支持JD Edwards日期和时间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

手头的主题是一个混乱的特定于域的问题,在Oracle的ERP软件JD Edwards中使用日期。其详细信息记录在此问题中。

The topic at hand is a messy domain-specific problem working with dates in Oracle's ERP software called JD Edwards. Its detail is documented in this question.

在编写用于处理来自JD Edwards的日期和时间的包装类之前,我想知道JodaTime或Java 8是否为这种独特的时间格式引入了任何特殊支持,或者无论我使用哪个库,我都必须进行重要的字符串操作。

Before writing wrapper classes for handling the dates and times from JD Edwards, I want to know if JodaTime or Java 8 introduced any special support for this unique time format, or if I'll have to do significant string manipulation regardless of the libraries I use.

这是一个模糊的问题,所以请仅在您具备此问题的特定知识和/或JodaTime / Java 8 / JSR 310时作出回应。

This is an obscure problem, so please only respond if you have specific knowledge of this problem, and/or JodaTime/Java 8/JSR 310.

附加:
按照Basil Bourque的要求,添加伴随上述日期的时间戳示例。以下是来自不同表的日期/时间字段的两个示例:

ADDITION: Per Basil Bourque's request, adding example of timestamps that accompany said dates. Here are two example of date/time fields from different tables:

JCSBMDATE:115100,JCSBMTIME:120102.0

JCSBMDATE:115100, JCSBMTIME:120102.0

RLUPMJ:114317,RLUPMT:141805.0

RLUPMJ:114317, RLUPMT:141805.0

此外,日期变量被转换为BigDecimal,时间是Double。所以,我可能会保留字符串解析器,但也会编写本地采用BigDecimal / Double值的工厂方法。

Also, the date variable is being cast as a BigDecimal and the time is a Double. So, I'll probably keep the string parsers around, but also write factory methods that take the BigDecimal/Double values natively as well.

似乎时间字段实际上是从一天开始的毫秒数(不是秒数),可以忽略.0。因此,必须执行转换和计算,如下所示:

It seems that the time field is actually the number of Milliseconds (not seconds) from the start of the day, and the ".0" can be ignored. So, one will have to perform a conversion and calculation like so:

localDate.atTime(LocalTime.ofNanoOfDay(Long.parseLong(jdeTime)* 1000000))

localDate.atTime(LocalTime.ofNanoOfDay(Long.parseLong(jdeTime) * 1000000))

推荐答案

JD Edwards日期定义



实际上 JD Edwards 日期不是那么血腥.oracle.com / cd / E26228_01 / doc.93 / e21961 / julian_date_conv.htm#WEAWX260rel =nofollow noreferrer> Oracle.com上的一页:

JD Edwards date defined

Actually the detail of a JD Edwards date is not so gory, according to this simple description on a page at Oracle.com:


关于Julian日期格式

About the Julian Date Format

JD Edwards World文件中的日期字段以Julian格式存储。 ...

Date fields in JD Edwards World files are stored in the Julian format. …

朱利安(* JUL)日期格式为CYYDDD,其中:

The Julian (*JUL) date format is CYYDDD, where:

C加到19到创造世纪,即0 + 19 = 19,1 + 19 = 20. YY是本世纪内的一年,DDD是一年中的一天。

C is added to 19 to create the century, i.e. 0 + 19 = 19, 1 + 19 = 20. YY is the year within the century, DDD is the day in the year.

条款:


  • 我会打电话给 C 部分a 世纪抵消,加入 19 多少个世纪。对于 19xx 年,使用 0 ,对于<$,使用 1 c $ c> 20xx 年。

  • java.time框架调用 DDD aDayOfYear ,序数日期是另一个术语。使用Julian作为一年中的一天数是常见的但不正确,与朱利安日

  • I would call the C part a "century-offset", how many centuries to add to 19. Use 0 for 19xx years, and 1 for 20xx years.
  • The java.time framework calls the DDD a "DayOfYear", and "ordinal date" is another term. The use of "Julian" for a day-number-within-a-year is common but not correct, conflicting with a Julian Day.

java.time框架不包括直接支持解析或生成此格式的字符串不是我能找到的。

The java.time framework does not include direct support for parsing or generating strings of this format, not that I can find.

java.time.temporal.JulianFields 但这些是针对重新定义的朱利安日期我们计算一个时代的天数(1970-01-01(ISO)而不是历史悠久的11月24日,公元前4714年(预感格里高利)),而忽略了几年。因此,这与JD Edwards定义无关,与问题中链接的该页面上的一些错误建议相反。

There is the java.time.temporal.JulianFields but those are for an redefined version of Julian dates where we count the number of days from an epoch (1970-01-01 (ISO) rather than the historic November 24, 4714 BC (proleptic Gregorian)), while ignoring years altogether. So this has nothing to do with the JD Edwards definition, contrary to some incorrect advice on that page linked in the Question.

此JD Edwards日期是序数日期的版本。序数日期有时被称为朱利安日期随意(和错误地),因为它与计算一系列天数的想法相同。但是,序数日期表示从年初到年末的天数,总数在1到365/366(闰年)之间,不计算自某个时代以来的数量并且增长到数千个。

This JD Edwards date is a version of an ordinal date. The ordinal date is sometimes referred to casually (and incorrectly) as a "julian" date only because it shares the idea of counting a sequence of days. But an ordinal date counts days from the beginning of the year to end of year for a number always between 1 and 365/366 (leap year), not counting since some epoch and growing into a number into the thousands.

返回问题,在java.time中处理JD Edwards日期......

Back to the Question, handling the JD Edwards date in java.time…

不,我没有找到任何直接或间接的支持java.time中内置的JD Edwards日期。

No, I do not find any direct or indirect support the JD Edwards date built into java.time.

java.date.format 包似乎没有意识到一个约会的世纪,只有年份和时代。所以我无法找到定义JD Edwards日期的 C 部分。

The java.date.format package seems unaware of the century of a date, only the year and the era. So no way that I can find to define the C part of a JD Edwards date.

JD Edwards日期的最后一部分,即一年中的序数天数,在日期时间类和格式化类中都得到很好的处理。

The last part of a JD Edwards date, the ordinal number of days in the year, is well-handled with within both the date-time classes and the formatting classes.

自JD Edwards日期起显然与java.time使用的ISO年表有相同的逻辑,唯一真正的问题是根据这种特定的格式解析和生成String对象。所有其他行为都可以从 LocalDate 中获利。

Since a JD Edwards date apparently has the same logic as the ISO chronology used by java.time, the only real issue at hand is parsing and generating String objects according to this particular format. All other behavior can be leveraged from a LocalDate.

因为我找不到定义 java.time.format.DateTimeFormatter 为此目的,我建议编写一个实用程序类来处理这些杂务。

Since I cannot find a way to define a java.time.format.DateTimeFormatter for this purpose, I suggest writing a utility class to handle these chores.

理想情况下我们会扩展 LocalDate class,覆盖其 解析 toString 方法。也许是 getCenturyOffset 方法。但 LocalDate 类标记为 final ,无法扩展。所以我会创建如下所示的类,包装 LocalDate

Ideally we would extend the LocalDate class, overriding its parse and toString methods. And perhaps a getCenturyOffset method. But the LocalDate class is marked final and cannot be extended. So I would create something like this class shown below, wrapping a LocalDate.

CAVEAT:使用风险由您自行承担。新鲜的代码,几乎没有运行,很难测试。仅作为一个例子,不用于生产。根据 ISC许可的条款使用。

CAVEAT: Use at your own risk. Fresh code, barely run, hardly tested. Meant as an example, not for use in production. Use according to terms of the ISC License.

package com.example.whatever;

import java.time.LocalDate;
import java.time.ZoneId;

/**
 * Wraps a 'LocalDate' to provide parsing/generating of strings in format known
 * as JD Edwards date.
 *
 * Format is CYYDDD where C is the number of centuries from 1900, YY is the year
 * within that century, and DDD is the ordinal day within the year (1-365 or
 * 1-366 in Leap Year).
 *
 * Immutable object. Thread-safe (hopefully! No guarantees).
 *
 * I would rather have done this by extending the 'java.time.LocalDate' class, but that class is marked 'final'.
 *
 * Examples: '000001' is January 1 of 1900. '116032' is February 1, 2016.
 *
 * © 2016 Basil Bourque. This source code may be used according to terms of the ISC License at https://opensource.org/licenses/ISC
 *
 * @author Basil Bourque
 */
public class JDEdwardsLocalDate {

    private LocalDate localDate = null;
    private int centuryOffset;
    private int yearOfCentury;
    private String formatted = null;

    // Static Factory method, in lieu of public constructor.
    static public JDEdwardsLocalDate from ( LocalDate localDateArg ) {
        return new JDEdwardsLocalDate ( localDateArg );
    }

    // Static Factory method, in lieu of public constructor.
    static public JDEdwardsLocalDate parse ( CharSequence charSequenceArg ) {
        if ( null == charSequenceArg ) {
            throw new IllegalArgumentException ( "Passed CharSequence that is null. Message # 0072f897-b05f-4a0e-88d9-57cfd63a712c." );
        }
        if ( charSequenceArg.length () != 6 ) {
            throw new IllegalArgumentException ( "Passed CharSequence that is not six characters in length. Message # eee1e134-8ec9-4c92-aff3-9296eac1a84a." );
        }
        String string = charSequenceArg.toString ();
        // Should have all digits. Test by converting to an int.
        try {
            int testAsInteger = Integer.parseInt ( string );
        } catch ( NumberFormatException e ) {
            throw new IllegalArgumentException ( "Passed CharSequence contains non-digits. Fails to convert to an integer value. Message # 0461f0ee-b6d6-451c-8304-6ceface05332." );
        }

        // Validity test passed.
        // Parse.
        int centuryOffset = Integer.parseInt ( string.substring ( 0 , 1 ) ); // Plus/Minus from '19' (as in '1900').
        int yearOfCentury = Integer.parseInt ( string.substring ( 1 , 3 ) );
        int ordinalDayOfYear = Integer.parseInt ( string.substring ( 3 ) );
        int centuryStart = ( ( centuryOffset + 19 ) * 100 ); // 0 -> 1900. 1 -> 2000. 2 -> 2100.
        int year = ( centuryStart + yearOfCentury );
        LocalDate localDate = LocalDate.ofYearDay ( year , ordinalDayOfYear );

        return new JDEdwardsLocalDate ( localDate );
    }

    // Constructor.
    private JDEdwardsLocalDate ( LocalDate localDateArg ) {
        this.localDate = localDateArg;
        // Calculate century offset, how many centuries plus/minus from 1900.
        int year = this.localDate.getYear ();
        int century = ( year / 100 );
        this.yearOfCentury = ( year - ( century * 100 ) ); // example: if 2016, return 16.
        this.centuryOffset = ( century - 19 );
        // Format as string.
        String paddedYearOfCentury = String.format ( "%02d" , this.yearOfCentury );
        String paddedDayOfYear = String.format ( "%03d" , this.localDate.getDayOfYear () );
        this.formatted = ( this.centuryOffset + paddedYearOfCentury + paddedDayOfYear );
    }

    @Override
    public String toString () {
        return this.formatted;
    }

    public LocalDate toLocalDate () {
        // Returns a java.time.LocalDate which shares the same ISO chronology as a JD Edwards Date.
        return this.localDate;
    }

    public int getDayOfYear () {
        // Returns ordinal day number within the year, 1-365 inclusive or 1-366 for Leap Year. 
        return this.localDate.getDayOfYear();
    }

    public int getYear () {
        // Returns a year number such as 2016. 
        return this.localDate.getYear();
    }

    public int getYearOfCentury () { 
        // Returns a number within 0 and 99 inclusive.
        return this.yearOfCentury;
    }

    public int getCenturyOffset () {
        // Returns 0 for 19xx dates, 1 for 20xx dates, 2 for 21xx dates, and so on.
        return this.centuryOffset;
    }

    public static void main ( String[] args ) {
        // '000001' is January 1, 1900.
        JDEdwardsLocalDate jde1 = JDEdwardsLocalDate.parse ( "000001" );
        System.out.println ( "'000001' = JDEdwardsLocalDate: " + jde1 + " = LocalDate: " + jde1.toLocalDate () + " Should be: January 1, 1900. " );

        // '116032' is February 1, 2016.
        JDEdwardsLocalDate jde2 = JDEdwardsLocalDate.parse ( "116032" );
        System.out.println ( "'116032' = JDEdwardsLocalDate: " + jde2 + " = LocalDate: " + jde2.toLocalDate () + " Should be: February 1, 2016." );

        // Today
        LocalDate today = LocalDate.now ( ZoneId.systemDefault () );
        JDEdwardsLocalDate jdeToday = JDEdwardsLocalDate.from ( today );
        System.out.println ( "LocalDate.now(): " + today + " = JDEdwardsLocalDate: " + jdeToday + " to LocalDate: " + jdeToday.toLocalDate () );
    }

}

运行时。


'000001'= JDEdwardsLocalDate:000001 = LocalDate:1900-01-01应该是:1900年1月1日。

'000001' = JDEdwardsLocalDate: 000001 = LocalDate: 1900-01-01 Should be: January 1, 1900.

'116032'= JDEdwardsLocalDate:116032 = LocalDate:2016-02-01应该是:2016年2月1日。

'116032' = JDEdwardsLocalDate: 116032 = LocalDate: 2016-02-01 Should be: February 1, 2016.

LocalDate.now(): 2016-05-09 = JDEdwardsLocalDate:116130 to LocalDate:2016-05-09

LocalDate.now(): 2016-05-09 = JDEdwardsLocalDate: 116130 to LocalDate: 2016-05-09



JD Edwards time-of-day



对于JD Edwards时间格式,我搜索了一下,找不到任何文档。如果你知道一些,请编辑你的问题以添加链接。 JDE时代唯一提到的似乎是从午夜开始的秒数。

JD Edwards time-of-day

As for JD Edwards time-of-day formats, I searched and could not find any documentation. If you know of some, please edit your Question to add links. The only mentions of JDE times seemed to be a count of seconds from midnight.

如果是这种情况(自午夜起计算),则 java.time.LocalTime 课程为您提供帮助。 LocalTime 可以实例化并读作:

If that is the case (a count since midnight), the java.time.LocalTime class has you covered. A LocalTime can be instantiated and read as either:

  • Whole seconds since start of day ( withSecond, ofSecondOfDay )
  • Fractional seconds since start of day, with a resolution of nanoseconds ( withNano, ofNanoOfDay )

纳秒分辨率意味着最多九位小数的位数。处理您提到的六位数没问题。只需进行数学计算,乘以/除以 1_000L 。请注意,这意味着可能的数据丢失,因为如果 LocalTime 值来自外部,您可能会截断分数的最后三位数(小数部分的第7位,第8位,第9位) JD Edwards数据。 [仅供参考,旧的java.util.Date/.Calendar类,以及Joda-Time,限制为毫秒分辨率,小数部分的三位数。]

Nanosecond resolution means up to nine digits of a decimal fraction. No problem handling the six digits you mentioned. Just do the math, multiply/divide by 1_000L. Just be aware that means possible data loss as you could be truncating those last three digits of fraction (7th, 8th, 9th digits of decimal fraction) if the LocalTime value came from outside of JD Edwards data. [FYI, the old java.util.Date/.Calendar classes, as well as Joda-Time, are limited to milliseconds resolution, for three digits of decimal fraction.]

不推荐:你可以做某种组合类,由 LocalDate LocalTime 。或者使用 LocalDateTime 。关键问题是时区。如果JD Edwards日期时间始终在某个时区(如UTC),那么组合并使用 OffsetDateTime 可能是有意义的。但是如果它没有特定的时区上下文,如果这些值只是日期时间的模糊概念而不是时间轴上的特定点,那么使用 LocalDateTime ,因为它具有没有时区。如果JDE始终为UTC,请使用 OffsetDateTime 设置为 ZoneOffset.UTC 。如果要指定时区(偏移加上规则来处理异常,例如 DST ),使用 ZonedDateTime

Not recommended: You could do some kind of combo class, composed of a LocalDate and a LocalTime. Or use a LocalDateTime. The key issue is time zone. If a JD Edwards date-time is always in a certain time zone such as UTC, then it might make sense to combine and use an OffsetDateTime . But if it has no specific time zone context, if the values are just a fuzzy idea of a date-time rather than specific points on the timeline, then use LocalDateTime as it has no time zone. If a JDE is always in UTC, use OffsetDateTime set to ZoneOffset.UTC. If you want to specify a time zone (an offset plus rules for handling anomalies such as DST), use ZonedDateTime.

建议:分别使用LocalTime。我不认为你想在业务逻辑中使用我的JDEdwardsLocalDate类,特别是因为它不是适合java.time框架的完整实现。 我的目的是在遇到JDE日期时使用该类立即将转换为 LocalDate 。同样适用于JDE时间,转换为 LocalTime 。如果其上下文始终为UTC,请创建 <$ c带有UTC的$ c> OffsetDateTime ,然后将其传递给您的业务逻辑。只回到JDE日期&必要时间(持久化到该JDE类型的数据库列,或向用户报告期望JDE演示)。

Recommended: Use a LocalTime separately. I do not think you want to be using my JDEdwardsLocalDate class in your business logic, especially because it is not a full implementation fitting into the java.time framework. My intention is to use that class to immediately convert to LocalDate when you encounter a JDE date. Same goes for a JDE time-of-day, convert to LocalTime immediately. If their context is always UTC, create an OffsetDateTime with UTC, and then pass that around your business logic. Only go back to a JDE date & time when necessary (persisting to database column of that JDE type, or reporting to user expecting that JDE presentation).

OffsetDateTime odt = OffsetDateTime.of( myLocalDate , myLocalTime , ZoneOffset.UTC );

如果JDE日期&时间暗示了一些其他背景,然后分配预期的时区。

If the JDE date & time has some other context implied, then assign the intended time zone.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.of( myLocalDate , myLocalTime , zoneId );

时区至关重要。您必须了解一般的概念。要清楚 LocalDate LocalTime LocalDateTime 时间轴上的片刻。 它们没有特定含义,直到您将它们调整为时区(或至少偏移从-UTC )。

Time zone is crucial here. You must understand the concepts in general. Be clear that LocalDate and LocalTime and LocalDateTime are not a moment on the timeline. They have no specific meaning until you adjust them into a time zone (or at least an offset-from-UTC).

此答案中包含的日期时间类型图表如果不熟悉java.time类型,可以帮助你。

My diagram of date-time types included on this Answer may help you if not familiar with the java.time types.

你必须理解JDE date&的含义。时间及其在您的应用/数据库中的使用。由于我无法找到有关JDE时间的任何信息,我无法了解JD Edwards对时区的意图。所以我不能提出更具体的建议。

And you must understand the meaning of JDE date & time and their use in your apps/databases. As I could not find anything about JDE time, I could not learn anything about the JD Edwards intentions towards time zones. So I cannot suggest anything more specific.

这篇关于JodaTime或Java 8是否有特殊支持JD Edwards日期和时间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆