I need to write the high performance function which calculates the new datetime based on given datetime and timeshift. It accept 2 arguments:
String, representing the date in format YYYYMMDDHHmm
Integer, representing the timeshift in hours
Function returns the string in format of 1st argument which is composed as result of applying the timeshift to 1st argument
It is known in advance that the first argument is always the same during the program lifetime.
My implementation has the following steps:
parsing 1st argument to extract the year,month,date, hours,min
creating GregorianCalendar(year, month, date, hours, min) object
applying method GregorianCalendar.add(HOUR,timeshift)
applying SimpleDateFormat to convert result back into string
Issue is that I do not take advantage from the fact that 1st argument is always the same.
If I will create a class member GregorianCalendar(year, month, date, hours, min), then after the 1st call to my function this object will be modified, which is not good, because I cannot reuse it for the following calls.
If you can, use the Joda-Time library, which makes date arithmetic very simple:
DateTime dt = new DateTime();
DateTime twoHoursLater = dt.plusHours(2);
They have a DateTimeFormatter class that you'd use to do the parsing of your input date-time string into a DateTime, eg:
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMddHHmm");
DateTime dt = fmt.parseDateTime(myDateString);
DateTime result = dt.plusHours(myTimeshiftInHours);
And Joda-Time interoperates well with java.util.Date too. I love it!
If the first argument is a value that will not change often, perhaps use a cache :
static private Map<String,Calendar> dateCache = new HashMap<String,Calendar>();
Then, in your method, check of the first argument (ex: String dateStr) is a key in the cache
Calendar cal;
if (dateCache.containsKey(dateStr)) {
cal = (Calendar)(dateCache.get(dateStr)).clone();
} else {
// parse date
cal = new GregorianCalendar(...);
dateCache.put(dateStr, (Calendar)cal.clone());
}
And add your timeshift value.
How about this,
Parse and hold on to your fixed date, call it fixedDate
Let timeShift be a time shift in hours, then Date shiftedDate = new Date(fixedDate.getTime() + (timeShift * 3600000)) would be your calculated shifted date (see this and this for understanding)
Apply SimpleDateFormat to convert shiftedDate to string.
Repeat steps 2 and 3 indefinitely, fixedDate is not modified and can be reused.
I'd try simple memoisation:
// This is not thread safe. Either give each thread has its own
// (thread confined) converter object, or make the class threadsafe.
public class MyDateConverter {
private String lastDate;
private int lastShift;
private String lastResult;
public String shiftDate(String date, int shift) {
if (shift == lastShift && date.equals(lastDate)) {
return lastResult;
}
// Your existing code here
lastDate = date;
lastShift = shift
lastResult = result;
return result;
}
}
Note this simple approach is most effective if the shift and date values rarely change. If either changes frequently, you'd need a more complicated cache, the code will be more complicated and the overheads (for a cache miss) will be higher.
If you simply want to avoid repeating step 1 (and maybe 2) again and again, parse the date once, then save the Date you get. You can then apply this date to your Calendar (with setDate()) before each add step again (or create a new GregorianCalendar, measure if it matters).
Related
When I do like below,
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.setTime(startTime); // startTime Date
DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar);
I get Output like 2015-04-15T11:04:30.000Z.
I want it to be like 2015-04-15T11:04:30.000.
Is there a way to achieve this?
Accepted answer or my Java seems to be outdated because I received this error:
The method newXMLGregorianCalendar(String) in the type DatatypeFactory is not applicable for the arguments (SimpleDateFormat)
and I didn't want to extend, so I solved it by removing timezone:
xmlCalendar.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
If you want to remove only "Z" from XMLGregorianCalendar object just call this method.
xmlDate.setTimezone( DatatypeConstants.FIELD_UNDEFINED )
Do it as follow
DatatypeFactory df;
try {
df = DatatypeFactory.newInstance();
return df.newXMLGregorianCalendar(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"));
} catch (DatatypeConfigurationException e) {
// throw new SomeRuntimeException(e);
}
Or Extend new class from XMLGregorianCalendar, override toXMLFormat and then delegate ALL the other methods to the contained instance.
class CustomXMLGregorianCalendar extends XMLGregorianCalendar
{
XMLGregorianCalendar calendar;
CustomXMLGregorianCalendar(XMLGregorianCalendar calendar){
this.calendar = calendar;
}
public String toXMLFormat() {
String text = calendar.toXMLFormat();
int pos = text.indexOf('Z');
return pos < 0 ? text : text.substring(0,pos);
}
public void setTimezone(int offset){ calendar.setTimezone( offset ); }
// ...
}
This is because your Locale Timezone, to achieve what you need transform the date using SimpleDateFormat:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
UPDATE when you comment:
I tried formatting it to a String then again parsing it to a Date. Then setting time in Calender object. Does not work. Still i get output as "2015-04-15T11:04:30.000Z"
You must understand that Calendar or Date objects are stored in it's own format, another thing is how you print them, so in this case, to see 2015-04-15T11:04:30.000Z in the Calendar representation does not matters, what you need is to have the correct date 2015-04-15 at 11:04:30 show this in the desired format is just to make user-friendly your output.
The output you get is from Calendar.toString() and the method doc says:
Return a string representation of this calendar. This method is intended to be used only for debugging purposes, and the format of the returned string may vary between implementations. The returned string may be empty but may not be null.
So in order to store the date and the time, your Calendar object is correct. In order to print it, you have to transform it into a String.
I had a similar issue. I'm putting this here for anyone that comes along after, but solved my issue similar to how Ignas Vaitekunas eventually did it.
I used
XMLGregorianCalendar xgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
xgc.setYear(year);
xgc.setMonth(month);
xgc.setDay(day);
xgc.setHour(hour);
xgc.setMinute(min);
xgc.setSecond(second);
xgc.setTimezone(timezone);
Where year, month, day, hour, min, second, timezone are all initially set to DatatypeConstants.FIELD_UNDEFINED.
I pull values from a formatted text field that's displayed to the user as ' - - T : : Z'. The user fills in what information they have, I split and parse the string and if I have a value for the timezone (or second, or minute, or hour etc) I set it, if not it gets fed to xgc as and undefined field. Then the XML Gregorian Calendar will print out only what values aren't undefined.
I had that situation and it was solved, using this line:
XMLGregorianCalendar dateNew = DatatypeFactory.newInstance().newXMLGregorianCalendar("2017-09-06T21:08:14");
I have this code in java which is about SystemTime:
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss");
//Gets the time of the boardtime object in milliseconds
public long getMs() {
return super.getTimeInMillis();
}
//Sets the time of the boardtime object in milliseconds
public void setMs(long ms) {
super.setTimeInMillis(ms);
}
I tried to convert it to C#:
For the first part, I used DateTimeFormatInfo class:
private static DateTimeFormatInfo sdf = new DateTimeFormatInfo();
for getting the system time in milliseconds I used TimeSpan:
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
I do not know if what I have done until now is correct or not but I can not find any C# equivalent for the setTime.
This is what I have done until now:
private static DateTimeFormatInfo sdf = new DateTimeFormatInfo();
public long getMs(){
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
return milliseconds;
}
public void setMs(long ms){
}
Thanks in advance
If you just want to set/get the time from milliseconds, you can do this with a C# TimeSpan:
private TimeSpan time
public void setMs(long ms)
{
this.time = TimeSpan.FromMilliseconds(ms);
}
public long getMs()
{
return this.time.TotalMilliseconds;
}
Your getMs() as defined above returns the number of MS since 1/1/0001 (see here). Based on this MSDN page, to set system time from C# you need to construct a SYSTEMTIME struct, initialize it properly, and pass it to the function SetSystemTime(). The page has a simple example that shows how to do that. How do we construct the right SYSTEMTIME struct? One can use the function FileTimeToSystemTime(), which takes the number of ticks since 1/1/1601 (note the different year) and converts it to a SYSTEMTIME.
So, in short:
In your setMs() function, convert the parameter that was passed (ticks since 1/1/0001) to ticks since 1/1/1601 (basically, subtract 1600 years in ticks)
Construct a FILETIME struct from that value
Call FileTimeToSystemTime() to get the corresponding SYSTEMTIME
Call SetSystemTime() and pass that value
If there's an easier way, I'd be interested to know. Hope this helps!
If you want to take the time as milliseconds, then use the TimeSpan.TotalMilliseconds method, constructed from a DateTime object using TimeSpan.FromTicks. Create a DateTime object and manipulate the timestamp using milliseconds, then use the predefined DateTime.AddMilliseconds method by adding resp. subtracting milliseconds:
var now = DateTime.Now; // or new DateTime(2014, 05, 29, 21, 27, 05);
Console.WriteLine(now.ToString("yyyy-MM-dd HH.mm.ss"));
var future = now.AddMilliseconds(1234567);
var past = now.AddMilliseconds(-1234567);
Console.WriteLine(future.ToString("yyyy-MM-dd HH.mm.ss"));
Console.WriteLine(past.ToString("yyyy-MM-dd HH.mm.ss"));
// get milliseconds from current date time object using TimeSpan.TotalMilliseconds
var ts = TimeSpan.FromTicks(now.Ticks);
Console.WriteLine(ts.TotalMilliseconds);
The output is:
2014-05-29 21.27.05
2014-05-29 21.47.40
2014-05-29 21.06.31
63536995625703,1
Have a look at this MSDN article about Custom Date and Time Format Strings for more custom date and time formatting options for a DateTime object.
I want know to how can I identifies if there is a date changes i.e. 23:59 to 00:00.
I am using a servlet. I can do it using a static String type variable and assign it to "dd" part of below returned date stamp and comparing it on every request with the current "dd" date stamp. If both "dd" part do not match then it will be sign of date change. Actually there is one static int type variable that I want to reset to zero which increment till the day change.
private static String getDate()
{
SimpleDateFormat customFormat = new SimpleDateFormat("HH:mm:ss dd-MM-yyyy");
return customFormat.format(new Date(System.currentTimeMillis()));
}
But how can I do it without comparing it, is there any better way to do it? Thanks.
How can I display only the last two digits of the current year without using any substring algorithms or any third party libraries?
I have tried the below method and it gave a four-digit year. I want to know whether there are any date formatting options available to get the current year in two-digit format.
Calendar.getInstance().get(Calendar.YEAR);
You can simply use the modulo operator:
int lastTwoDigits = Calendar.getInstance().get(Calendar.YEAR) % 100;
Edit: Using a SimpleDateFormat, as #R.J proposed, is the better solution if you want the result to be a string. If you need an integer, use modulo.
You can use a SimpleDateFormat to format a date as per your requirements.
DateFormat df = new SimpleDateFormat("yy"); // Just the year, with 2 digits
String formattedDate = df.format(Calendar.getInstance().getTime());
System.out.println(formattedDate);
Edit: Depending on the needs/requirements, either the approach suggested by me or the one suggested by Robin can be used. Ideally, when dealing with a lot of manipulations with the Date, it is better to use a DateFormat approach.
This is a one-liner:
System.out.println(Year.now().format(DateTimeFormatter.ofPattern("uu")));
I am using java.time.Year, one of a number of date and time classes introduced in Java 8 (and also backported to Java 6 and 7). This is just one little example out of very many where the new classes are more convenient and lead to clearer code than the old classes Calendar and SimpleDateFormat.
If you just wanted the two-digit number, not as a string, you may use:Year.now().getValue() % 100.
The other answers were good answers in 2013, but the years have moved on. :-)
Edit: New Year doesn’t happen at the same time in all time zones. To make the dependency on time zone clear in the code I would usually write Year.now(myDesiredTimeZoneId), for example in the form Year.now(ZoneId.systemDefault()).
String.format() also has Date/Time Conversions.
To get the last two digits of the current year,
String.format("%ty", Year.now());
This works with a number of the java.time classes, including Year, YearMonth, LocalDate, LocalDateTime, and ZonedDateTime.
In Kotlin
Call this function and pass time in parameter
Example :
Input Parameter : "2021-08-09T16:01:38.905Z"
Output : 09 Aug 21
private val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private val outputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
fun calculateDateMonthYear(time: String): String {
val inputTime = inputFormat.parse(time)
val convertDateMonthYear = outputFormat.format(inputTime!!)
val timeInMilliseconds = outputFormat.parse(convertDateMonthYear)!!
val mTime: Calendar = Calendar.getInstance()
mTime.timeInMillis = timeInMilliseconds.time
val date_cal = SimpleDateFormat("dd")
val month_date = SimpleDateFormat("MMM")
val year_cal = SimpleDateFormat("yy")
val date = date_cal.format(mTime.time)
val month_name = month_date.format(mTime.time)
val year = year_cal.format(mTime.time)
return "$date $month_name $year"
}
The solution of #Robin Krahl is a bit hacky but I like it. We could avoid the cases commented by #Albert Tong if we add a leading zero. In order that we have the last two digits of the year, I suppose that the result should be a String. In case we could not use the solution of #jaco0646. We could do this:
String yearStr = addLeadingZero(Calendar.getInstance().get(Calendar.YEAR) % 100)
private String addLeadingZero(int num) {
String result = String.valueOf(num);
if(num < 10){
result = "0" + result;
}
return result;
}
I know the question asked for how to do this in Java but Google sent me here when asking about Groovy, so I'll add my answer for that here.
I came up with this based on the Java answer provided by Rahul:
String lastTwoYearDigits = new Date().format("yy")
This question already has answers here:
Java Date cut off time information
(20 answers)
Closed 8 years ago.
I want to implement a thread-safe function to remove the time part from java.util.Date.
I tried this way
private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
public static Date removeTimeFromDate(Date date) {
Date returnDate = date;
if (date == null) {
return returnDate;
}
//just have the date remove the time
String targetDateStr = df.format(date);
try {
returnDate = df.parse(targetDateStr);
} catch (ParseException e) {
}
return returnDate;
}
and use synchronized or threadLocal to make it thread-safe.
But it there any better way to implement it in Java. It seems this way is a bit verbose.
I am not satisfied with it.
A Date object holds a variable wich represents the time as the number of milliseconds since epoch. So, you can't "remove" the time part. What you can do is set the time of that day to zero, which means it will be 00:00:00 000 of that day. This is done by using a GregorianCalendar:
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
gc.set(Calendar.HOUR_OF_DAY, 0);
gc.set(Calendar.MINUTE, 0);
gc.set(Calendar.SECOND, 0);
gc.set(Calendar.MILLISECOND, 0);
Date returnDate = gc.getTime();
A Date holds an instant in time - that means it doesn't unambiguously specify a particular date. So you need to specify a time zone as well, in order to work out what date something falls on. You then need to work out how you want to represent the result - as a Date with a value of "midnight on that date in UTC" for example?
You should also note that midnight itself doesn't occur on all days in all time zones, due to DST transitions which can occur at midnight. (Brazil is a common example of this.)
Unless you're really wedded to Date and Calendar, I'd recommend that you start using Joda Time instead, as that allows you to have a value of type LocalDate which gets rid of most of these problems.