Year-Week-Day in java.time? - java-time

Is there support in the java.time classes, or its extension ThreeTen-Extra, for a week dates, specifically a Year-Week-Day such as 2009-W53-7 which is Sunday 3 January 2010.
As for the year-week without the day-of-week:
My Answer to the Question, java get week of year for given a date, explains using IsoFields to handle the year-week.
The ThreeTen-Extra project that extends the java.time classes offers the YearWeek class.
But how to represent the day-of-week as well?

See the IsoFields class, which allows the week-based year and week of week-based year to be queried. There is also a dedicated formatter ISO_WEEK_DATE.
The DayOfWeek enum tells you the number of the day-of-week, 1-7 for Monday to Sunday. Call LocalDate::getDayOfWeek and then DayOfWeek::getValue.
LocalDate ld = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;
2016-12-07
int weekOfWeekBasedYear = ld.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int yearOfWeekBasedYear = ld.get( IsoFields.WEEK_BASED_YEAR ) ;
int dayOfWeek = ld.getDayOfWeek().getValue();
Use these parts to build strings in the standard ISO 8601 week date formats.
String yearWeek = yearOfWeekBasedYear + "-W" + String.format( "%02d", weekOfWeekBasedYear ) ;
2016-W49
String yearWeekDay = yearWeek + "-" + dayOfWeek ;
2016-W49-3
Or, let the predefined DateTimeFormatter.ISO_WEEK_DATE do the work.
String ywd = ld.format( DateTimeFormatter.ISO_WEEK_DATE );
2016-W49-3
That same formatter can parse such standard strings.
String input = "2016-W49-3" ;
LocalDate ldParsed = LocalDate.parse( input , DateTimeFormatter.ISO_WEEK_DATE ) ;
2016-12-07

Related

convert date format yywwd to dd-mm-yy

In Access, I would like to convert a date column in format yywwd to dd-mm-yy. (weekday nr. 1 is monday, and years can only from 2000 and later, so e.g. today (monday 15-06-2020) would be 20251 what I would like to be converted to 15-06-2020.
I'm not much of a coder so honestly asside from messing with Datepart I have not tried a whole lot. Does anyone have suggestion?
It seems that the function 'GetDayFromWeekNumber' mentioned here vba convert week number (and year) to date? could work but how is this used in MSAccess?
Thanks a lot in advance!
I have a function that works in Excel to convert YYWWD to a date, this should be very similar if not identical to the code needed in Access. It is quite verbose so you could probably make it simpler, but at least the calculation steps are clearly set out.
The function assumes the ISO definition of week number - i.e. the first week of the year is the week in which the 4th of Jan falls. The first day of a week is Monday, the last day of a week is Sunday.
Function dateFromYYWWD(yywwd)
Dim sYYWWD As String
Dim sYYYY As String
Dim ww As Integer
Dim d As Integer
Dim fourthOfJan As Date
Dim fourthOfJanWeekday As Integer
Dim week1StartDate As Date
Dim targetWeekStartDate As Date
Dim targetDate As Date
' Convert to string if not already
sYYWWD = "" & yywwd
' Get the year in full
sYYYY = "20" + Left(sYYWWD, 2)
' Get the week number and day in the week
ww = CInt(Mid(sYYWWD, 3, 2))
d = CInt(Right(sYYWWD, 1))
' Calculate the date of 4th Jan in the same year
fourthOfJan = CDate(sYYYY & "-01-04")
' Get the day of week of the 4th Jan
' NOTE - CALCULATES MONDAY AS DAY 1 OF THE WEEK, SUNDAY AS DAY 7
fourthOfJanWeekday = Weekday(fourthOfJan, vbMonday)
' Date of the first day of week #1 in the target year
week1StartDate = fourthOfJan - fourthOfJanWeekday + 1
' First day of the target week
targetWeekStartDate = week1StartDate + (ww - 1) * 7
' Target date
targetDate = targetWeekStartDate + d - 1
dateFromYYWWD = targetDate
End Function
It's as simple as this:
Public Function ConvertFromYYWWD(s) As Date
Dim t&
t = DateSerial(2000 + Mid(s, 1, 2), 1, 1) + 7 * (Mid(s, 3, 2) - 1)
ConvertFromYYWWD = t - Weekday(t, vbMonday) + Mid(s, 5, 1)
End Function
Just place the above function in a code module in the database project.
You mentioned in the comments under your question that the week number is always two digits. I am assuming the the year number is likewise always two digits.
The first task is to split the value:
YWDDate = 20251
Year = YWDDate \ 1000 + 2000
2020
Week = (YWDDate Mod 1000) \ 10
25
Weekday = YWDDate Mod 10
1
Then, as this probably is ISO 8601 week numbering, the year is not the calendar year but the ISO 8601 year, which native VBA knows nothing about, thus a custom function is needed:
' First day of the week.
WeekStart = DateYearWeek(25, 2020, vbMonday)
' Requested day of week (which here is the same)
WeekDate = DateAdd("d", 1 - 1, WeekStart)
The function is not that convoluted:
' Returns the date of Monday for the ISO 8601 week of IsoYear and Week.
' Optionally, returns the date of any other weekday of that week.
'
' 2017-05-03. Gustav Brock, Cactus Data ApS, CPH.
'
Public Function DateYearWeek( _
ByVal IsoWeek As Integer, _
Optional ByVal IsoYear As Integer, _
Optional ByVal DayOfWeek As VbDayOfWeek = VbDayOfWeek.vbMonday) _
As Date
Dim WeekDate As Date
Dim ResultDate As Date
If IsoYear = 0 Then
IsoYear = Year(Date)
End If
' Validate parameters.
If Not IsWeekday(DayOfWeek) Then
' Don't accept invalid values for DayOfWeek.
Err.Raise DtError.dtInvalidProcedureCallOrArgument
Exit Function
End If
If Not IsWeek(IsoWeek, IsoYear) Then
' A valid week number must be passed.
Err.Raise DtError.dtInvalidProcedureCallOrArgument
Exit Function
End If
WeekDate = DateAdd(IntervalSetting(dtWeek), IsoWeek - 1, DateFirstWeekYear(IsoYear))
ResultDate = DateThisWeekPrimo(WeekDate, DayOfWeek)
DateYearWeek = ResultDate
End Function
but - as you can see - it calls some helper functions, which again call other functions, which will be too much to post here.
I can upload it somewhere, if you feel this will provide a solution for you.

Error java.time.format.DateTimeParseException: could not be parsed, unparsed text found at index 10

I´m trying to pase the next String using LocalDateTime, but I always get de unparsed text found error:
Error java.time.format.DateTimeParseException: Text '2016-08-18 14:27:15.103+02' could not be parsed, unparsed text found at index 10
Here is my String: convertDate: '2016-08-18 14:27:15.103+02'
And my code:
public static LocalDate conversorStringToLocalDateTime(String convertDate) throws ParseException {
LocalDate dateTime =LocalDate.parse(convertDate);
return dateTime;
}
I guess is not too complicated, buy I´m not able to see the error. Could the +02 in the String be the cause?
tl;dr
OffsetDateTime odt = OffsetDateTime.parse ( "2016-08-18 14:27:15.103+02" , DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss.SSSX" ) ) ;
Details
The Answer by greg-449 is correct about the problem (using a date-only object for a date-time value) but not the solution.
That Answer uses LocalDateTime which unnecessarily throws away valuable information about the offset-from-UTC. A LocalDateTime does not represent a specific moment on the timeline, only a vague idea about possible moments depending on adjusting into a particular time zone.
The +02 is an offset-from-UTC meaning “two hours ahead of UTC”. So in UTC the time-of-day for this simultaneous moment is 12 hours, 2 hours less than your 14 hours. This does represent a specific moment on the timeline. This offset is the valuable information you are throwing away with a LocalDateTime rather than an OffsetDateTime.
The format of your string is in SQL format, which is close to standard ISO 8601 format. Merely replace the SPACE in the middle with a T. The java.time classes use ISO 8601 formats by default, so no need to specify a formatting pattern.
String input = "2016-08-18 14:27:15.103+02";
String inputModified = input.replace ( " " , "T" );
Unfortunately, Java 8 has a bug in parsing offset values abbreviated to just an hour or offset values omitting the colon between hours and minutes. Fixed in Java 9. But in Java 8, we need to adjust the input.
// Workaround for Java 8 where 2-digit offset fails parsing. Fixed in Java 9.
int lengthOfAbbreviatedOffset = 3;
if ( inputModified.indexOf ( "+" ) == ( inputModified.length () - lengthOfAbbreviatedOffset ) ) {
// If third character from end is a PLUS SIGN, append ':00'.
inputModified = inputModified + ":00";
}
if ( inputModified.indexOf ( "-" ) == ( inputModified.length () - lengthOfAbbreviatedOffset ) ) {
// If third character from end is a PLUS SIGN, append ':00'.
inputModified = inputModified + ":00";
}
Now parse.
OffsetDateTime odt = OffsetDateTime.parse ( inputModified );
Dump to console. Note how we transformed +02 into +02:00.
System.out.println ( "input: " + input + " | inputModified: " + inputModified + " | odt: " + odt );
input: 2016-08-18 14:27:15.103+02 | inputModified: 2016-08-18T14:27:15.103+02:00 | odt: 2016-08-18T14:27:15.103+02:00
Alternatively, specify a formatting pattern. The offset-parsing bug does not bite when using this formatting pattern.
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss.SSSX" );
OffsetDateTime odt = OffsetDateTime.parse ( input , f );
Database
Coming from Postgres, you should be retrieving the value as a date-time object rather than a String.
If your JDBC driver complies with JDBC 4.2 you can call ResultSet::getObject to get an Instant or OffsetDateTime. If not, call ResultSet::getTimestamp to get a java.sql.Timestamp, then immediately convert to java.time by calling toInstant on the Timestamp object.
Stick with java.time for your business logic; use the java.sql types briefly and only for exchange with the database.
Your code is using LocalDate which only parses a date - not a date and time so you are getting an error when the parse finds the space after the date.
So you should be using LocalDateTime but LocalDateTime.parse(String) expects an ISO format date which is not the format you are using.
So you need to use a DateTimeFormatter to specify the format of your input string. Something like:
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSX");
LocalDateTime result = LocalDateTime.parse(convertDate, format);

Day from date Scala

I'd like to get the day from a date object as an integer. This is my code so far.
val dateString = "2015-11-24 23:23:09"
val format = new java.text.SimpleDateFormat("yyyy-MM-dd H:m:s")
val date = format.parse(dateString)
print(date) # this gives Tue Nov 24 23:23:09 CST 2015
Now, from date, I want to get the day of the month as an integer. How do I do that?
Thanks.
Just use the Java Calendar class (although I would recommend moving over to the Joda library if you are doing much serious work with dates/times):
val cal = Calendar.getInstance()
cal.setTime(date)
val dayOfMonth = cal.get(Calendar.DAY_OF_MONTH)
tl;dr
LocalDateTime.parse(
"2015-11-24 23:23:09".replace( " " , "T" )
).getDayOfMonth()
java.time
The modern approach uses the java.time classes.
Using Java syntax here as I don't know Scala. Note that java.time uses immutable objects.
Convert your string to comply with ISO 8601 standard format with a T in the middle.
String input = "2015-11-24 23:23:09".replace( " " , "T" ) ;
Parse as an LocalDateTime as your input lacks any time zone or offset-from-UTC.
LocalDateTime ldt = LocalDateTime.parse( input ) ;
Interrogate for the day of month.
int dom = ldt.getDayOfMonth() ;
Using Joda,
org.joda.time.DateTime.now().getDayOfMonth()
or equivalently,
import java.util.Date
new org.joda.time.DateTime(new Date()).getDayOfMonth

Current date from BlackBerry

I am developing an application which needs the current date from the device, but it only needs day-of-week, month, and day-of-month, like Friday October 14
I have tried this code with Calendar. How do I convert Date to String? Is this possible to get date in this format?
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
System.out.println("Date" + c.getTime());
and my output : `Fri Oct 14 16:17:03 Asia/Calcutta 2011`
You could use SimpleDateFormat:
SimpleDateFormat fmt = new SimpleDateFormat("EEEE MMMM dd");
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
System.out.print("Date ");
System.out.println(fmt.format(c.getTime()));
If you need those values in different Strings it gets a little bit more complicated (using DateFormatSymbols to get the month/weekday names):
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
DateFormatSymbols dateSymbols = new DateFormatSymbols();
String[] monthsText = dateSymbols.getMonths();
String[] weekdaysText = dateSymbols.getWeekdays();
String day = String.valueOf(c.get(Calendar.DAY_OF_MONTH));
String month = monthsText[c.get(Calendar.MONTH)];
String weekday = weekdaysText[c.get(Calendar.DAY_OF_WEEK)];
System.out.format("day: %s, month: %s, weekday: %s", day, month, weekday);

What is the precise definition of JDE's Julian Date format?

I am writing code to convert from a Gregorian date to a JDE (J.D.Edwards) Julian date.
Note: a JDE Julian date is different from the normal usage of the term Julian date.
As far as I can work out from Googling, the definition of a JDE Julian date is:
1000*(year-1900) + dayofyear
where year is the 4-digit year (e.g. 2009), and dayofyear is 1 for 1st January, and counts up all year to either 365 or 366 for 31st December (depending whether this is a leap year).
My question is this: are years before 1900 supported? If so, does the above formula still hold, or should it be this:
1000*(year-1900) - dayofyear
(note minus instead of plus.)
or something else?
Does anyone have a link to the official documentation for this date format?
The JDE Julian date consists of CYYDDD which is Century, Year, Day of year.
Century is zero for 20th e.g. 19XX and one for 21st e.g. 20XX.
The year is two digits.
So 101001 is 1 January 2001
As you can see this will not support dates before 1900.
See this Oracle page for a simple and official explanation: About the Julian Date Format
The "JDE Julian Date Converter" does return a negative value for:
1809/07/23 : -90635
As opposed to the classical Julian Date:
The Julian date for CE 1809 July 23 00:00:00.0 UT is
JD 2381986.50000
Here is a example of JD EDWARDS (AS/400 software) Julian Date, but that is not an "official" documentation and it does not seems to support dates before 1900...
Note: this "ACC: How to Convert Julian Days to Dates in Access and Back" does not support date before 1900 either... as it speaks about an "informal" Julian day, commonly used by government agencies and contractors.
The informal Julian day format used in this article is the ordinal day of a year (for example, Julian day 032 represents February 1st, or the 32nd day of the year).
Variations on informal Julian day formats include using a preceding two-digit year (for example 96032 for 2/1/96) and separating the year with a dash (for example 96-032).
Another, less popular, Julian day format uses a one digit year (for example 6-032). These additional formats do not uniquely identify the century or decade. You should carefully consider the consequences when using these formats; for example, the Julian day 00061 can be interpreted as 3/1/2000 or 3/2/1900.
Update: Sorry, JDE is probably something else. But for reference:
The JDE I know is different. From page 59 in the book
"Astronomical algorithms" (Jean Meeus, ISBN 0-943396-35-2):
"If the JD corresponds to an instant
measured in the scale of Dynamical
Time (or Ephemeris Time), the
expression Julian Ephemeris Day
(JDE) is generally used. (Not JED as
it is sometimes written. The 'E' is a
sort of index appended to 'JD')"
JD and JDE (for the same point in time) are close in value
as the difference UT and ET is on the order of minutes. E.g. ET-UT was 56.86 seconds in 1990 and -2.72 seconds in 1900.
There is also MJD (Modified Julian Day):
MJD = JD - 2400000.5
Zero point for MJD is 1858-11-17, 0h UT.
Note that JD as Julian date is a misnomer. It is
Julian day. The JD has nothing to do with the Julian
calendar. (This is in disagreement with the Wikipedia article, this
is from the author of the book mentioned above, Jean Meeus - a Belgian astronomer specializing in celestial mechanics.)
Maybe off from the question, you can convert in Excel using the following formula:
Convert Julian to Date in Excel
In Cell A2 place a Julian date, like 102324
in Cell B2 place this formula: (copy it in)
=DATE(YEAR("01/01/"&TEXT(1900+INT(A2/1000),0)),MONTH("01/01/"&TEXT(1900+INT(A2/1000),0)),DAY("01/01/"&TEXT(1900+INT(A2/1000),0)))+MOD(A2,1000)-1
The date 11/20/02 date will appear in cell B2
Convert Date to Julian in Excel
In Cell C2 copy this formula:
=(YEAR(B2)-2000+100)*1000+B2-DATE(YEAR(B2),"01","01")+1
This will convert B2 back to 102324
Save the below source code in a source member called JDEDATES. Use the runsqlstm on the first line to create the functions. You can then do things like
select jde2date(A1UPMJ), f.* from f00095 f
and see a real date.
Source:
--RUNSQLSTM SRCFILE(qtxtsrc) SRCMBR(JDEDATES) COMMIT(*NONE) NAMING(*SQL)
-- jde 2 date
create function QGPL/jde2date ( d decimal(7,0))
returns date
language sql
deterministic
contains sql
SET OPTION DATFMT=*ISO
BEGIN
if d=0 then return null;
else
return date(digits(decimal(d+1900000,7,0)));
end if;
end; -- date 2 jde
create function QGPL/date2jde ( d date)
returns decimal(7,0)
language sql
deterministic
contains sql
SET OPTION DATFMT=*ISO
BEGIN
if d is null then return 0;
else
return (YEAR(D)-1900)*1000+DAYOFYEAR(D);
end if;
end ;
Several years late to the party, but for other folks like me that find yourselves working with legacy systems like this, I hope some of my java snippets can help. I'm leveraging the fact that you can convert this CYYDDD format into yyyyDDD format and parse based on that.
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Calendar;
import java.util.SimpleDateFormat;
String jdeJulianDate = "099365"; //Testing with December 31, 1999
// Compile what the year number is
int centIndex = Integer.parseInt(jdeJulianDate.substring(0,1));
int yearIndex = Integer.parseInt(jdeJulianDate.substring(1,3));
int yearNumber = 1900 + (100 * centIndex) + yearIndex;
// Put the year number together with date ordinal to get yyyyDDD format
String fullDate = String.valueOf(yearNumber) + jdeJulianDate.substring(3,6);
// Date parsing, so need to wrap in try/catch block
try {
Date dt = new SimpleDateFormat("yyyyDDD").parse(fullDate);
// Validate it parses to a date in the same year...
Calendar cal = new GregorianCalendar();
cal.setTime(dt);
if (cal.get(Calendar.YEAR) != yearNumber) {
// Cases happen where things like 121366 (should be invalid) get parsed, yielding 2022-01-01.
// Throw exception or what-not here.
}
}
catch (Exception e) {
// Date parsing error handling here
}
A sample of VBA code to convert back and forth between JDE Julian Date and Gregorian:
Public Const Epoch = 1900
Public Const JDateMultiplier = 1000
Public Const FirstJan = "01/01/"
Public Function Julian2Date(ByVal vDate As Long) As Date
Dim Year As Long
Dim Days As Long
Dim SeedDate As Date
' Day Number
Days = vDate - (Int(vDate / JDateMultiplier) * JDateMultiplier) - 1
' Calendar Year
Year = ((vDate - Days) / JDateMultiplier) + Epoch
' First Day of Calendar Year
SeedDate = CDate(FirstJan + CStr(Year))
' Add Number of Days to First Day in Calendar Year
Julian2Date = DateAdd("d", Days, SeedDate)
End Function
Public Function Date2Julian(ByVal vDate As Date) As Long
Dim JYear As String
Dim BeginDate As Date
Dim JDays As Long
' Calendar Year
JYear = Format(Year(vDate), "0000")
' First Day of Calendar Year
BeginDate = CDate(FirstJan + JYear)
' Day Number
JDays = DateDiff("d", BeginDate, vDate) + 1
' Add Number of Days to Year Number
Date2Julian = ((CLng(JYear) - Epoch) * JDateMultiplier) + JDays
End Function
I have tried to make it as clear and simple as possible, and to this end I have intentionally left out any error trapping. However, you should be able to add the code to a VBA module and call them directly from your own code.
I also include some useful snippets of T-SQL:
Todays Date as JDE Julian Date:
(datepart(yy,getdate())-1900) * 1000 + datepart(dy, getdate())
Convert JDE Julian Date to Gregorian (DD/MM/YYYY), replace XXXXXX with the column name containing the JDE Julian Date:
convert (varchar, dateadd (day,convert (int, right(XXXXXX,3)) - 1, convert (datetime, ('1/1/' + convert ( varchar, (cast(left(right(XXXXXX+1000000,6),3) as varchar) + 1900))))),103)
If you require a different Gregorian format, replace the 103 value (right at the end) with the applicable value found here: https://msdn.microsoft.com/en-us/library/ms187928.aspx
I have an easy way for C using time now and epoch 1970, 01, 01 midnight if anybody is interested.
But this is for Julian Day Numbers which is not the same as JDE but they are similar in respect to using math to compute days and I'm sure this idea could be adapted for JDE. Sometimes people just confuse the two like I do. Sorry. But still this is an example of using a time reference which should always be done and since most computers use this it would be just as easy for us not to get too bogged down in dates and just use days before or after this epoch.
Since JDE is now owned by Oracle, they also now support Julian_Day. see:
https://docs.oracle.com/javase/8/docs/api/java/time/temporal/JulianFields.html
#include <stdio.h>
#include <time.h>
#define EPOCH (double) 2440587.5 /* Julian Day number for Jan. 01, 1970 midnight */
int main ()
{
double days = time(0)/86400.0;
printf ("%f days since January 1, 1970\n", days);
printf ("%f\n", days + EPOCH);
return 0;
}
Wow, there's a lot of complicated code in some of these answers just to convert to and from JDE julian dates. There are simple ways in Excel and VBA to get there.
FROM JULIAN
Excel (assuming julian date is in A1):
=DATE(1900+LEFT(A1,LEN(A1)-3),1,RIGHT(A1,3))
VBA (from julian date, j, stored as String):
d = DateSerial(1900 + Left$(j, Len(j) - 3), 1, Right$(j, 3))
VBA (from julian date, j, stored as Long):
d = DateSerial(1900 + Left$(j, Len(CStr(j)) - 3), 1, Right$(j, 3))
TO JULIAN
Excel (assuming date is in A1):
=(YEAR(A1)-1900)*1000+A1-DATE(YEAR(A1),1,0)
VBA (to a Long, j):
j = (Year(d) - 1900) * 1000 + DatePart("y", d)