Create a date, insert it into database, compare, it's different - sql

The goal
I've got a really strange problem. My goal is to compare a dynamic date in database using dbunit (the database is an Oracle one). This dynamic date is the today date (comparing static date works...)
The experimentation
To compare date, I use this very simple code :
#Test
public void simpleDateTest() throws DatabaseUnitException, SQLException {
// create a date corresponding to today
Date today = new Date();
// load a dataset
IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(getClass()
.getResource("/dataset.xml"));
// replace [TODAY] by the today date
ReplacementDataSet rDataSet = new ReplacementDataSet(expectedDataSet);
rDataSet.addReplacementObject("[TODAY]", today);
// insert the dataset
DatabaseConnection connection = getConnection();
DatabaseOperation.CLEAN_INSERT.execute(connection, rDataSet);
// do a simple query to get some fields, em is the entity manager which uses the same connection as above
Query q = em
.createNativeQuery("SELECT ID, MY_DATE FROM MY_TABLE");
List<Object[]> result = q.getResultList();
// compare the date with today date
assertEquals(today.getTime(), ((Date) result.get(0)[1]).getTime());
}
With the following dataset :
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<MY_TABLE ID="1" MY_DATE="[TODAY]" />
</dataset>
The problem
I don't know why, but the assert failed ! When comparing the two dates, there is a very few milliseconds difference. The error is something like that :
java.lang.AssertionError: expected:<1358262234801> but was:<1358262234000>
I don't understand how is it possible to have different dates because they are quite normally the same !
Any clue to understand the problem and how to solve it ?

The Oracle Date type doesn't have a resolution of milliseconds, it only has a resolution of seconds.
When saving a time to the database the milliseconds are simply stripped off. When you look at the actual value you see that the last three digits are all zero.

Assuming that today is a java.util.Date, the Java Date has millisecond precision. An Oracle date, on the other hand, does not have millisecond precision. So you would expect to lose some precision when you store a java.util.Date in Oracle and retrieve it back.
You could store the data in an Oracle timestamp column-- that will have millisecond precision. Or you could strip off the milliseconds from the Java Date before writing it to the database.

Related

Compare Dates in Kotlin

How can i compare Dates in Kotlin?
I have the Date of an Event as a String (Format:dd/mm/yy) and I want to check if it is within the next 7 Days of the current Date.
The time in this case is not relevant or if needet I would use midnight.
Can someone please help me with this?
In my current code i got both Dates by this:
val date = document.data["Date"].toString() //Example: 22/08/22 (dd/MM/yy)
val today = SimpleDateFormat("dd/MM/yy").format(Date()).toString()
this is within a Android environment.
I can't get the date more specific because i am getting it from a Database.
Parse string into LocalDate using its parse method. There’s no out-of-the-box DateTimeFormatter for dd/mm/yy format, but you can trivially create one using DateTimeFormatter.ofPattern.
Get current date using LocalDate.now().
diff = ChronoUnit.DAYS.between(now, date1)

How to convert unix timestamp into Date

I am trying to convert Unix time stamp into date
final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
final String startdate = Instant.ofEpochSecond(Long.parseLong(requestVO.getStartDate().toString()))
.atZone(ZoneId.of("GMT-4"))
.format(formatter);
final String enddate = Instant.ofEpochSecond(Long.parseLong(requestVO.getEndDate().toString()))
.atZone(ZoneId.of("GMT-4"))
.format(formatter);
above is what I have tried for the format of date Mentioned in DateTimeFormatter and requestVO.getStartDate() is giving Date type value.I am applying the startDate and endDate in sql query Like below
and ceo.erx_date between '"+startdate+"' and '"+enddate+"'
No compilation errors getting But, giving number format exception.
If requestVo.getStartDate() returns a Date object, your error is here:
Long.parseLong(requestVo.getStartDate())
As the documentation says, Long.parseLong(String) throws
NumberFormatException - if the string does not contain a parsable long.
Try this:
Long.parseLong(requestVo.getStartDate().getTime())
In every case two things:
Take care from NullPointerException: check if your date is null or not
Use preparedStatement and not string concatenation when write e query in Java
There are at least two reasons to use PreparedStatement instead of Statement:
They are faster then simple Statement: because Statement are compiled and execute every time, but PreparedStatment are compiled once
In case of PreparedStatement you are safe from the point of view of SQL injection
tl;dr
myJavaUtilDate // The terrible `java.util.Date` class is the legacy way to represent a moment in UTC.
.toInstant() // `Instant` is modern way to represent a moment in UTC.
.atZone( // Adjust from UTC to some time zone.
ZoneId.of( "America/Martinique" ) // Specify the time zone you had in mind for an offset of four hours behind UTC.
) // Returns a `ZonedDateTime` object.
.format( // Generate text representing the value of our `ZonedDateTime` object's content.
DateTimeFormatter.ISO_LOCAL_DATE_TIME // A predefined formatter per ISO 8601 that omits any indication of time zone or offset-from-UTC.
)
.replace(
"T" , // Standard ISO 8601 formats use a `T` between the date and time-of-day portions.
" "
) // Returns a `String`.
java.util.Date::toInstant
requestVO.getStartDate() is giving Date type value.
You are working too hard.
Convert the terrible Date class object to its modern replacement, Instant. Notice how the legacy classes were given new methods for conversion to/from the modern java.time classes. Look for to… & from… methods on the old classes. In this case, Date::toInstant.
Instant instant = myJavaUtilDate.toInstant() ;
Zone versus offset
.atZone(ZoneId.of("GMT-4"))
Nope, -4 is not a time zone. That is an offset.
An offset-from-UTC is merely a number of hours-minutes-seconds ahead or behind the prime meridian.
A time zone is much more. A time zone is a history of the past, present, and future changes in offset used by the people of a particular region. A time zone carries a name in format of Continent/Region such as Asia/Kolkata or Pacific/Auckland.
Better to use a time zone than a mere offset. For one thing, you may be wrong about the offset. By using an time zone, java.time will determine the offset in effect at your intended moment.
Zone for offset of four hours behind UTC
Perhaps by -4 you have in mind a time zone such as America/Martinique, America/Aruba, or America/Puerto_Rico.
ZoneId z = ZoneId.of( "America/Puerto_Rico" ) ;
Instant + ZoneId ➡ ZonedDateTime
Apply that ZoneId to produce a ZonedDateTime object. Same moment, different wall-clock time.
ZonedDateTime zdt = instant.atZone( z ) ;
Generating text
Produce a string in standard ISO 8601 format, wisely extended to append the name of the zone in square brackets.
String output = zdt.toString() ;
But you wanted a format similar to ISO 8601, but without the T in the middle and with no indicator of offset/zone. I do not recommend reporting a moment without representing the time zone or offset. But if you insist:
String output =
zdt
.format( DateTimeFormatter.ISO_LOCAL_DATE_TIME )
.replace( "T" , " " )
;

java.sql.SQLException: ORA-01843: not a valid month error - date format conversion issue

I'm having a strange issue here with a query from which I'm trying to pull data queried by start and end date parameters.
I'm conducting the following.
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
String preparedQuery = "SELECT ID, FULNAME, FRMEMAIL, LOCATION,TYPE1,TYPE2,BORROWER_NAME,LOAN_NUM,TIME_REQ
FROM FORM_REDUCVU WHERE to_date(TIME_REQ,'yyyy-mm-dd') >= ? AND to_date (TIME_REQ,'yyyy-mm-dd') <= ? ORDER BY ID DESC";
java.util.Date util_StartDate = sdf.parse( request.getParameter("time_req_date") );
java.sql.Date timreq_datevar1 = new java.sql.Date( util_StartDate.getTime() );
java.util.Date util_EndDate = sdf.parse( request.getParameter("time_req_date2") );
java.sql.Date timreq_datevar2 = new java.sql.Date( util_EndDate.getTime() );
out.println("datestamp java time vals "+timreq_datevar1 + " " + timreq_datevar2);
PreparedStatement prepstmt = connection.prepareStatement(preparedQuery);
prepstmt.setDate(1, timreq_datevar1);
prepstmt.setDate(2, timreq_datevar2);
And the out.print values will give something like 2018-10-09 and 2019-02-20.
This does match the date picker selections I'm making, which are in mm/dd/yyyy format, i.e. 10/09/2018 and 02/20/2019.
Now the above returns no errors in the log, but no data either. But I did have the SQL query as "
WHERE to_datechar(TIME_REQ,'mm/dd/yyyy') >= ? AND to_char(TIME_REQ,'mm/dd/yyyy') <= ?
When changing to this above, I get the error in the topic of not a valid month.
I would have thought the SimpleDateFormat class would have parsed the date to mm/dd/yyyy in pattern, but it seems to make the java.slq.Date object pattern hyphenated, like yyyy-mm-dd.
Am I not parsing it correctly? Or is this going to require a different class or package, like java.Time? I would thought this would work, but there has to be some small conversion method not working.
Bottom line - I'd really prefer to keep the jQuery date pickers with their mm/dd/yyyy formats in tact, and be able to query by these entries.
Any input regarding this is welcomed.
Thank you!
Do NOT use to_date() on a column that is alread a DATE to_date() will convert the date to a varchar just to convert it back to a DATE which it was to begin with.
So your condition should be:
WHERE TIME_REQ >= ? AND TIME_REQ <= ?
You are correctly using setDate() so Oracle performs a date to date comparison - there is no need to convert the date in the database to a string value.
Ideally you should use java.time.LocalDate and setObject() instead of java.sql.Date though (however not all Oracle driver versions support that)

Conevrt chararray to Date and add duration in Pig

Iam new to Pig and I have a sample test data of 500 KB which I need to multiply several times to make the file size bigger for some test purpose. The single row in my data is as follows:
( card_description:chararray,
transaction_date:chararray,
merchant_name:chararray,
merchant_city:chararray,
transaction_amount:float
) ;
I want to simply change the transaction_amount and transaction_date for each row several times and then join all the results to make a single big file.
I am stuck in trying to change the transaction_date.
The date value in the file is
27/05/2010 00:00
r1 = FOREACH data GENERATE card_description,ToDate(transaction_date),merchant_name,merchant_city,
ROUND(RANDOM()*5)*transaction_amount;
result =union data,r1;
In order to alter the transaction datei want to use AddDuration function, but in trying to convert chararray to date, I am facing format related issues and unable to understand the solution.
Can someone guide?
After checking out the ways you can invoke ToDate, currently you are invoking ToDate as:
ToDate(milliseconds)
ToDate(iosstring)
And your format is not in milliseconds, nor follows the ISO 8601 format. You should be invoking it like:
ToDate(userstring, format)
Where format is a pattern string that follows these rules.
Therefore, ToDate should be called like:
-- For a 12hr clock
ToDate(transaction_date, "yyyy/MM/dd hh:mm")
-- For a 24hr clock
ToDate(transaction_date, "yyyy/MM/dd HH:mm")
For AddDuration, remember that the second parameter you provide to it must be a string in the ISO 8601 format. Make sure to read the link so you format the string correctly.

character_length Teradata SQL Assistant

I have to run column checks for data consistency and the only thing that is throwing off my code is checking for character lengths for dates between certain parameters.
SEL
sum(case when ( A.date is null or (character_length(A.date) >8)) then 1 else 0 end ) as Date
from
table A
;
The date format of the column is YYYY-MM-DD, and the type is DA. When I run the script in SQL Assistant, I get an error 3580 "Illegal use of CHARACTERS, MCHARACTERS, or OCTET_LENGTH functions."
Preliminary research suggests that SQL Assistant has issues with the character_length function, but I don't know how to adjust the code to make it run.
with chareter length are you trying to get the memory used? Becuase if so that is constant for a date field. If you are trying to get the length of the string representation i think LENGTH(A.date) will suffice. Unfortanatly since teradata will pad zeros on conversions to string, I think this might always return 10.
UPDATE :
Okay so if you want a date in a special 'form' when you output it you need to select it properly. In teradata as with most DBs Date are not store in strings, but rather as ints, counting days from a given 'epoch' date for the database (for example the epoch might be 01/01/0000). Each date type in teradata has a format parameter, which places in the record header instructions on how to format the output on select. By default a date format is set to this DATE FROMAT 'MM/DD/YYYY' I believe. You can change that by casting.
Try SELECT cast(cast(A.date as DATE FORMAT 'MM-DD-YYYY') as CHAR(10)) FROM A. and see what happens. There should be no need to validate the form of the dates past a small sample to see if the format is correct. The second cast forces the database to perform the conversion and use the format header specified. Other wise what you might see is the database will pass the date in a date form to SQL Assitant and sql assitant will perform the conversion on the application level, using the format specified in its own setting rather then the one set in the database.