Spring + Hibernate + MS SQL server - UTC time zone - sql-server

I have developed simple application with Spring 4.2.5 + Hibernate 5.1.0 - database system is MS SQL Server 2014.
From few days I am struggling with correct storing time + timezone in database.
Requirements that I need to fulfill is:
Save all dates in UTC time zone.
Store timezone in database column value.
To achieve it I created model called MyComment:
#Entity
#Table(name = "MY_COMMENT")
#EntityListeners(value = { MyCommentListener.class })
#Audited
public class MyComment implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Long id;
#Column(name = "DATE_", nullable = false)
private Timestamp date;
...
}
To enforce saving dates in UTC time zone I used Jadira framework:
hibProperties.put("jadira.usertype.autoRegisterUserTypes", true);
hibProperties.put("jadira.usertype.javaZone", "UTC");
hibProperties.put("jadira.usertype.databaseZone", "UTC");
However during each create/update operation of MyComment object, MyCommentListener is getting date from my local timezone (not UTC date!):
public class MyCommentListener {
#PreUpdate
#PrePersist
public void setLastUpdate(MyComment myComment) {
myComment.setDate(new Timestamp(System.currentTimeMillis()));
}
}
Do you know how can I solve this issue?
Should I use other date type in my model? Different than Timestamp?
What kind of type should be DATE_ column in MS SQL server database?
I will appreciate any help. Thank you.

AFAIK, the problem is with listener. Replace the following code in listener and verify. Change the date format as per your need.
#PreUpdate
#PrePersist
public void setLastUpdate(MyComment myComment) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
myComment.setDate(dateFormat.getCalendar().getTime());
}

You can set a timezone property in the application properties file as below.
spring.jpa.properties.hibernate.jdbc.time_zone=UTC

It was very strange for me that there's no property in Spring to set up default TimeZone - at least I do not know about it.
After some googling I found out that the best place in Spring to set time zone is WebApplicationInitializer, so I prepared following code:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
setupTimeZone();
}
private void setupTimeZone() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
}

Related

Flutter wrong utc time from SQL Server database

I've got a problem with flutter recognizing my DateTime as UTC time. Via http request, I am storing some data inside my SQL Server database which contains a UTC DateTime. This is done via Entity Framework.
var workingTime = new WorkingTime()
{
StartDateTime = dto.StartDateTime.ToUniversalTime(),
EndDateTime = dto.EndDateTime.ToUniversalTime(),
...
};
await _repository.AddAsync(workingTime);
This looks quiet okay, the request was done at 2020-06-13 01-59-41:690 in Germany, so the stored data is the correct UTC time.
Now I am loading these data in my flutter app and if I debug my app, the loaded datetime says, that it is not a UTC time.
I am not sure, if I store the data wrong, or if I the parsing inside flutter is wrong, but I can't see me doing something wrong here.
Please tell me if you need code or more information.
Edit
So after a lot of testing, I found out something:
Debug.WriteLine(model.EndDateTime.Kind);
This prints "Unspecified". It seems like there is something wrong either in storing the DateTime or in reading from it.
Be explicit about the UTC every time. Indicate to the compiler you want the UTC time.
To get millisecondsSinceEpoch in UTC time:
DateTime dateTime=DateTime.now().toUtc();
int epochTime = dateTime.toUtc().millisecondsSinceEpoch;
To get Datetime in UTC:
DateTime dt=DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch).toUtc();
Store time as int in database. Milliseconds since epoch time.
DateTime dateTime=DateTime.now().toUtc();
int epochTime = dateTime.toUtc().millisecondsSinceEpoch;
After a lot of thinking I came along a good method for my case. I ended up implementing an extension method, that converts the Kind of every DateTime stored inside the Database to the UTC Kind when loaded.
Inside the DataContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Convert all DateTimes to UTC
modelBuilder.TreatDateTimeAsUtc();
}
The extension method
public static class ModelBuilderExtensions
{
public static void TreatDateTimeAsUtc(this ModelBuilder modelBuilder)
{
var dateTimeConverter = new ValueConverter<DateTime, DateTime>(
v => v.ToUniversalTime(),
v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
var nullableDateTimeConverter = new ValueConverter<DateTime?, DateTime?>(
v => v.HasValue ? v.Value.ToUniversalTime() : v,
v => v.HasValue ? DateTime.SpecifyKind(v.Value, DateTimeKind.Utc) : v);
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType == typeof(DateTime))
{
property.SetValueConverter(dateTimeConverter);
}
else if (property.ClrType == typeof(DateTime?))
{
property.SetValueConverter(nullableDateTimeConverter);
}
}
}
}
}

Conflict between spring-data-cassandra and spring-data-solr

I'm currently working in project that needs Cassandra database to have search ability. We've got DataStax cluster and we want to use Spring Data to simplify database operations. However, when we made entity that got both - #Table (for cassandra) and #SolrDocument (for Solr) it happened to be broken. The only error we got is the one below. Anyone have encountered such a problem?
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property findAll found for type ENTITYNAME!
I know that this is probably Spring issue, but hope to find someone who have fought this type of problem.
Greetings!
Some sample entity causing problems:
#SolrDocument(solrCoreName = "sample_entity")
#Table("sample_entity")
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public final class SampleEntity {
#PrimaryKey
#Indexed(name = "id")
private UUID id;
private LocalDateTime created;
private UUID foreignId;
#Indexed(name = "name")
private String name;
private boolean someflag = true;
}
You're mixing up things - if you're using DSE Search, then it's better to perform search via CQL, by querying in the solr_query column. In your example, the #SolrDocument will force using of the Solr's HTTP API, while #Table will force use of CQL.
You can use Object Mapper from DataStax to map classes to tables, like this:
// STest.java
#Table(keyspace = "test",name = "stest")
public class STest {
#PartitionKey
private int id;
private String t;
}
// STestAccessor.java
#Accessor
public interface STestAccessor {
#Query("SELECT * FROM test.stest WHERE solr_query = :solr")
Result<STest> getViaSolr(#Param("solr") String solr);
}
// STestMain.java
MappingManager manager = new MappingManager(session);
STestAccessor sa = manager.createAccessor(STestAccessor.class);
Result<STest> rs = sa.getViaSolr("*:*");
for (STest sTest : rs) {
System.out.println("id=" + sTest.getId() + ", text=" + sTest.getT());
}
Here is the full code.

Best Practise for Handling Date in Spring Data MongoDb

I am running into few issues around handling dates in my project. This is what I have.
In My Entities, I am using ZonedDateTime.
private ZonedDateTime assignedOn;
Have Configured converters in Spring to handle this
public static class ZonedDateTimeToDateConverter implements Converter {
public static final ZonedDateTimeToDateConverter INSTANCE = new ZonedDateTimeToDateConverter();
private ZonedDateTimeToDateConverter() {}
#Override
public Date convert(ZonedDateTime source) {
return source == null ? null : Date.from(source.toInstant());
}
}
public static class DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {
public static final DateToZonedDateTimeConverter INSTANCE = new DateToZonedDateTimeConverter();
private DateToZonedDateTimeConverter() {}
#Override
public ZonedDateTime convert(Date source) {
return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
I see that data is stored in Mongodb as ISO date. This what i see in Mongodb.
"completed_on" : ISODate("2017-04-12T20:02:40.000+0000"),
My Question is related to querying these date fields using Spring. If I want to find all the records (equals operator) matching only the date part and not the time part, what should be the approach? I saw example in this thread
Spring data mongodb search for ISO date
Which suggest something like this.
query.addCriteria(Criteria.where("created").ne(null).andOperator(
Criteria.where("created").gte(DateUtils.getDate("2016-04-14 00:00:00", DateUtils.DB_FORMAT_DATETIME)),
Criteria.where("created").lte(DateUtils.getDate("2016-04-14 23:59:59", DateUtils.DB_FORMAT_DATETIME))
));
Just wanted to see if this is the only approach or there's another elegant way to do this?

play framekwork 2.2. - ebean model save time from request

i have these model
#Entity
#Table(name = "recipe")
public class Recipe extends Model {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public Long id;
#NotNull
#Constraints.Required
public String title;
#Column(name = "short_description")
public String shortDescription;
#Column(columnDefinition = "TEXT")
public String ingredients;
#Column(columnDefinition = "TEXT")
public String cooking;
#NotNull
#Constraints.Required
#Formats.DateTime(pattern="HH:mm:ss")
public Time time;
now i'd like to save data comming from angular js with restangular. all parameters were provieded in the controller but i get a error:
{"time":["Invalid value"]}
all data were strings in the request. i guess thats the problem. but i don't want cast it by my self, because then i loose the play form validation...
do you can give me any hints?
thanks a lot!
Java and dates/times do not play nice together unfortunately. I would remove the #Formats annotation and just pass in the 'unix time' because that is what the Time class expects. You can do this pretty easily on the angular side by implementing the momentjs library. if you are getting the dates in the format HH:mm:ss then in your angular controller use the following code to format the time to unix time:
var time = moment(str, "HH:mm:ss").format("X");
where str is a string represtation of the time you are formatting. then pass time in as the parameter.
if i completely misunderstood the question and you are retrieving the time from the database and not saving the time to the database then just flip the above method.
var time = moment(str, "X").format("HH:mm:ss");
where str is the time you retrieved from the database.

New instance in RIA Domain Service

I'm using .NET RIA Services July Preview to communicate between my Silverlight client and my server. On my server I have an ASP.NET project hosting the Silverlight application. In the ASP.NET application I have a Linq-to-Sql DataModel with a table called Hour. I have extended the Hour entity with 3 properties by creating Hour.shared.cs:
public partial class Hour
{
public string CustomerName { get; set; }
public string ProjectName { get; set; }
public string FullProjectName { get { return this.CustomerName + " - " + this.ProjectName; } }
}
In my domainservice I have a get-method called GetHours. Due the design in Linq, I cannot explicit create a new instance of the Hour entity and through the new entity set the values of my new properties:
var query = from hours in this.Context.Hours
select new Hour()
{
HourID = hours.HourID,
ProjectName = "Hello World"
};
If I just select hours it works just fine but I need to set the ProjectName and CustomerName some how.
Any ideas about how to get around this?
Trying my answer again, last time SO froze on me.
Probably the easiest way to do this would be using a function:
public Hour PopulateHour(Hour hour)
{
hour.CompanyName = "xyz";
hour.ProjectName = "123";
return hour;
}
Then you can use this in your linq query:
var query = from hour in this.Context.Hours
select PopulateHour(hour);
One thing that would make this easier would be if you already had the CompanyId and ProjectId as properties in the Hour class.

Resources