I'm a beginner in java and I with my code below I can generate a random time in "hh:mm:ss" format . I have no idea how to tweak my code to display time in "hh:mm" format as I am not familiar with the
Date and Time java libraries . I have checked posts here like converting time from hh:mm:ss to hh:mm in java but it does not help here .
import java.util.Random;
import java.sql.Time;
final Random random = new Random();
final int millisInDay = 24*60*60*1000;
Time time = new Time((long)random.nextInt(millisInDay));
I have also tried :
// creates random time in hh:mm format for 0-12 hours but I want the full 24 hour timeline
public static String createRandomTime() {
DateFormat format = new SimpleDateFormat("h.mm aa");
String timeString = format.format(new Date()).toString();
return timeString;
}
I would appreciate your help .
You could write a method that creates proper random hours and random minutes, then construct a java.time.LocalTime of them and return a desired String representation.
Here's an example:
public static String createRandomTime() {
// create valid (in range) random int values for hours and minutes
int randomHours = ThreadLocalRandom.current().nextInt(0, 23);
int randomMinutes = ThreadLocalRandom.current().nextInt(0, 59);
// then create a LocalTime from them and return its String representation
return LocalTime.of(randomHours, randomMinutes).format(
// using a desired pattern
DateTimeFormatter.ofPattern("HH:mm")
);
}
Executing that method ten times in a main like this
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(createRandomTime());
}
}
will produce an output like (not necessarily equal to)
08:16
07:54
17:15
19:41
14:24
12:00
12:33
11:00
09:11
02:33
Please note that the int values and corresponding LocalTime created from them will not change if you just want another format. You can easily switch the pattern to another one (maybe make the pattern String a parameter of the method). E.g. you could make it "hh:mm a" for Strings like 10:23 AM.
Since you're using the SimpleDateFormat, I'd suggest taking a look to its documentation
In there, you can see that h is for hour in AM/PM format. Since you want the 24h format, you'll need either H or k, depending if you want it to be 0-23 or 1-24
You can try with the following code,
public void testDateFormat() {
String format = "HH:mm"; //24 hours format
//hh:mm aa for 12 hours format
DateFormat dateFormat = new SimpleDateFormat(format);
String date = dateFormat.format(new Date());
System.out.println(date);
}
There is a fantastic Javadoc is available to explain the details of various options. Please refer the Javadoc as well https://docs.oracle.com/javase/10/docs/api/java/text/SimpleDateFormat.html
Related
we run a REST-webservice which consumes different data, my current issue belongs to a date, received as String and parsed by a java.text.SimpleDateFormat (java 8):
We received a lot (>50k) of 'wrong' formatted Strings, which were parsed by the SimpleDateFormat anyways.
The SimpleDateFormat is configured with the pattern "yyyy-MM-dd".
We received Strings the other way around "dd-MM-yyyy".
For Example the String "07-07-1950" was parsed to the date "0012-10-31" (Starting from July in year 7, added 1950 days).
We fixed the implementation, so these Strings are now parsed as expected. But we have all the corrupt dates in the system. The final question is now:
Is there a way to conclude from the date "0012-10-31" to possible original inputs (e.g. "07-07-1950", "07-06-1980" and maybe more...)?
Best regards
I found a way to find possible inputs:
I can use Calendar to iterate through possible dates, parsing the dates in the "wron"g way, and build a map with these information.
public static Map<String, Collection<String>> createDateMapping() throws ParseException
{
final DateFormat targetFormat = new SimpleDateFormat("yyyy-MM-dd");
final DateFormat wrongFormat = new SimpleDateFormat("dd-MM-yyyy");
//starting today
final Calendar cal = Calendar.getInstance();
final Map<String, Collection<String>> inputMappings = new HashMap<>();
//rolling down to year zero is quite time consuming, back to year 1899 should be enough...
while (cal.get(Calendar.YEAR) > 1899)
{
//creating the "wrong" date string
final String formattedDate = wrongFormat.format(cal.getTime());
final String key = targetFormat.format(targetFormat.parse(formattedDate));
if (!inputMappings.containsKey(key))
{
inputMappings.put(key, new ArrayList<>());
}
inputMappings.get(key).add(targetFormat.format(cal.getTime()));
//roll calendar to previous day
cal.roll(Calendar.DAY_OF_YEAR, false);
if (cal.get(Calendar.DAY_OF_YEAR) == 1)
{
//roll down the year manually, since it is not rolled down automatically
cal.roll(Calendar.DAY_OF_YEAR, false);
//roll down the day again, to start at the last day of the year again
cal.roll(Calendar.YEAR, false);
}
}
return inputMappings;
}
by the use of this method I can:
final Map<String, Collection<String>> dateMapping = createDateMapping();
System.out.println(dateMapping.get("0012-10-31"));//[2011-05-07, 1980-06-07, 1950-07-07, 1919-08-07]
It will not solve the problem completely, but is at least a good starting point - hopefully there are some dates with more explicit results.
Building on Martin Ackermann's answer:
First of all, I simplified the code a bit.
public static Map<String, Set<LocalDate>> createDateMapping(LocalDate min, LocalDate max) throws ParseException {
DateFormat targetFormat = new SimpleDateFormat("yyyy-MM-dd");
DateTimeFormatter wrongFormat = DateTimeFormatter.ofPattern("dd-MM-yyyy");
final Map<String, Set<LocalDate>> inputMappings = new LinkedHashMap<>();
for (LocalDate date = min; !date.isAfter(max); date = date.plusDays(1)) {
final String incorrectlyFormattedDate = date.format(wrongFormat);
final String key = targetFormat.format(targetFormat.parse(incorrectlyFormattedDate));
if (!inputMappings.containsKey(key)) {
inputMappings.put(key, new TreeSet<>());
}
inputMappings.get(key).add(date);
}
return inputMappings;
}
Easily fixing the invalid dates depends on what is the range of valid dates.
For example if max=2016-12-31 then the following table shows the number of unique dates that are fixable/ambiguous depending on min
min fixable ambiguous
-----------------------------
1990-01-01 9862 0
1980-01-01 8827 2344
1970-01-01 5331 5918
1960-01-01 1832 9494
1950-01-01 408 10950
1940-01-01 314 11054
1930-01-01 218 11160
1920-01-01 165 11223
1910-01-01 135 11263
1900-01-01 105 11303
Ambiguous matches for invalid dates occur at about 30 year intervals so if the actual dates fall in a period of 30 years then you are in luck
LocalDate max = LocalDate.of(2016, Month.DECEMBER, 31);
LocalDate min = max.minusYears(30);
Map<String, Set<LocalDate>> invalidDateMapping = createDateMapping(min, max);
long reversibleCount = invalidDateMapping.entrySet().stream().filter(e -> e.getValue().size() == 1).count(); // 10859
long ambiguousCount = invalidDateMapping.size() - reversibleCount; // 50
I don't think you will be able to figure out the original date of the corrupted input, but you should be able to find all corrupted dates and perhaps find a way to re-consume that data. This is because each date was altered by an unknown number of days, and reversing that process would require you to know either the number of days or the starting date, and it looks like you don't have that here.
That said, it will actually be fairly easy to narrow down any dates that were corrupted.
The largest value you will be given for a month should be 12. That means the latest "year" for your corrupted data will be the year 12. If your dates run right up to the present, the largest year (which was incorrectly parsed as days) will be 2016, which would be converted to about 5.5 years. So any dates with years below 18 or 19 are corrupted, and you should be able to at least remove them.
The only edge case here is if you have dates that have years that will validly land in the early teens. If that's the case, you'd have to go through those by hand. But that seems unlikely.
Have you tried setting SimpleDateFormat Lenient to false
package test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat dateFormat2 = new SimpleDateFormat("dd-MM-yyyy");
dateFormat1.setLenient(false);
dateFormat2.setLenient(false);
Date d = null;
String invalidDate = "07-06-1980";
try {
d = dateFormat1.parse(invalidDate);
} catch (Exception e) {
System.out.println("reversed date " + invalidDate);
d = dateFormat2.parse(invalidDate);
}
System.out.println(parsed date " + dateFormat1.format(d));
}
}
reversed date 07-06-1980
parsed date 1980-06-07
This question already has answers here:
how to get a list of dates between two dates in java
(23 answers)
Closed 6 years ago.
I'm trying to get an array of Dates, while my input is a 'from'/'to' structure.
So my input is:
String date1 = "2014-01-01";
String date2 = "2014-05-01";
My output should be an Arraylist with all dates between date1 and date2.
I've already looked for this, but I could only find questions about the difference between 2 dates:
SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";
try {
Date date1 = myFormat.parse(inputString1);
Date date2 = myFormat.parse(inputString2);
long diff = date2.getTime() - date1.getTime();
System.out.println ("Days: " + TimeUnit.DAYS.convert(diff,TimeUnit.MILLISECONDS));
} catch (ParseException e) {
e.printStackTrace();
}
Any hints or suggestions? All other questions are for iOS or SQL.
Take a look at JodaTime: http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTime.html
DateTime dateTime1 = new DateTime(date1);
DateTime dateTime2 = new DateTime(date2);
List<Date> allDates = new ArrayList();
while( dateTime1.before(dateTime2) ){
allDates.add( dateTime1.toDate() );
dateTime1 = dateTime1.plusDays(1);
}
Below is the code to get array of dates between the two string date.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
public class DateFormatExample {
public static void main(String[] args) {
// TODO Auto-generated method stub
SimpleDateFormat myFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String date1 = "2014-01-01";
String date2 = "2014-05-01";
try {
Date d1 = myFormat.parse(date1);
Date d2 = myFormat.parse(date2);
List<Date> allDates = new ArrayList<Date>();
List<String> allDatesString = new ArrayList<String>();
while( d1.before(d2) ){
d1 = addDays(d1, 1);
allDates.add(d1);
allDatesString.add(formatter.format(d1));
}
System.out.println(allDates);
System.out.println(allDatesString);
} catch (ParseException e) {
e.printStackTrace();
}
}
private static Date addDays(Date d1, int i) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(d1);
cal.add(Calendar.DATE, 1);
return cal.getTime();
}
}
If you don't want to use third party libraries you can use Calendar:
Check here a working demo.
public static void main(String[] args) throws Exception {
SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";
ArrayList<Date> dates = new ArrayList<Date>();
try {
Date date1 = myFormat.parse(inputString1);
Calendar c1 = DateToCalendar(date1);
Date date2 = myFormat.parse(inputString2);
Calendar c2 = DateToCalendar(date2);
while (!areEqualDate(c1, c2)) {
dates.add(c1.getTime());
System.out.println (c1.getTime());
c1.add(Calendar.DAY_OF_YEAR, 1);
}
} catch (ParseException e) {
e.printStackTrace();
}
// ArrayList<Date> dates >> contain all dates between both given days.
}
private static boolean areEqualDate(Calendar c1, Calendar c2) {
if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)) return false;
if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)) return false;
if (c1.get(Calendar.DAY_OF_YEAR) != c2.get(Calendar.DAY_OF_YEAR)) return false;
return true;
}
public static Calendar DateToCalendar(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal;
}
I like JodaTime, but this can also be done without 3rd party libraries by using java.util.Calendar. Given a Calendar object, one can use its add method to increase certain fields of the date while honoring the calendar rules (like adding 1 day to the 31st of January gets you to the 1st of February, not to the 32nd of January).
First get the dates into one Calendar object each, in the correct chronological order so adding is going in the right direction later:
Calendar cStart = Calendar.getInstance(),
cStop = Calendar.getInstance();
if (date1.before(date2)) {
cStart.setTime(date1);
cStop.setTime(date2);
} else {
cStart.setTime(date2);
cStop.setTime(date1);
date1 and date2 are the parsed Date objects from your question, for simplicity's sake.
Next, loop over an "add 1 to day-of-year" instruction until this gets you beyond the stop date:
do {
System.out.println(pretty(cStart));
cStart.add(Calendar.DAY_OF_YEAR, 1);
} while (cStart.before(cStop));
And lastly print the stop date
System.out.println(pretty(cStop));
pretty() is just some mini method sending the calendar through a SDF, like the one you used for parsing the Strings in the first place.
This solution will print the date range, including the start and stop dates, and might need some tweaking around the edge cases (like date1==date2). Can be easily adapted to exclude the start and stop dates. Printing can be swapped for aggregation of course. To get a Date object from the calendar, use the getTime() method (returns a snapshot, not a live reference).
The documentation for the relevant (Gregorian)Calendar can be found here.
In case you are using Guava, there is a very elegant solution to this problem.
Guava has two neat classes, such as Range and ContiguousSet, which implement exactly what you need: first one operates on ranges of values, and second one - is able to convert a range to a set of discrete values.
Example of usage of both (together with JodaTime):
LocalDate start = LocalDate.parse("2015-01-01");
LocalDate end = LocalDate.parse("2019-02-01");
Range<LocalDate> range = Range.closed(start, end); //Creates a "closed" range, that is both dates are inclusive. There are also options like "openClosed", "closedOpen" and "open"
final Set<LocalDate> daySet = ContiguousSet.create(range, LocalDateDomain.INSTANCE); //Create a "virtual" set of days in given the range. "virtual" part means that if you create a set of 10 thousand years, it will not eat your memory at all
for (LocalDate day : daySet) {
//...operation...
}
Personally, I really prefer this way, as it eliminates some problems with understanding closed/open ranges, and makes code much easier to read and understand, while making no impact on performance. Also, it works with any kinds of dates, any libraries (you can swap YodaTime to Java8 Dates or even Java7- Date-based implementation).
Moreover, it allows you to do some neat operations on ranges like intersections, unions, spanning of ranges, incredibly fast "contains" and so on.
Only downsides are:
Dependence on Guava.
Need to create a special "DiscreteDomain" class, which Guava uses to understand where one date ends and other begins.
Example of LocalDateDomain implementation which operates as a bridge between Guava and JodaTime:
public class LocalDateDomain extends DiscreteDomain<LocalDate> {
public static final LocalDateDomain INSTANCE = new LocalDateDomain();
#Override
public LocalDate next(LocalDate value) {
return value.plusDays(1);
}
#Override
public LocalDate previous(LocalDate value) {
return value.minusDays(1);
}
#Override
public long distance(LocalDate start, LocalDate end) {
return Days.daysBetween(start, end).getDays();
}
}
I already know that OP isn't using Java 8 but here's the current solution - Java has been revamped and the new java.time API does every conceivable job in that regard:
//change these values :
LocalDate ld1 = LocalDate.ofEpochDay(0);
LocalDate ld2 = LocalDate.now();
//do NOT change these:
final LocalDate begin = ld1.isBefore(ld2) ? ld1 : ld2;
final LocalDate end = ld2.isAfter(ld1) ? ld2 : ld1;
for (int i = 0; i < begin.until(end, ChronoUnit.DAYS); i++) {
final LocalDate curDate = begin.plusDays(i);
System.out.println("current date : " + curDate);
}
This will output every valid day between the two dates whereas most of the other solutions will also give you invalid ones; heres the thing: temporal calculations need to be done on timezone-independent data - the output on the other hand may very well be timezone and/or chronology -dependent.
Thats why there are packages like java.time.format - simply calculate your time/date values and format them for your chosen region ... thats how its done correctly.
If you need to convert temporal input there are also useful functions in the time-API, i recommend doing a thorough tutorial on the subject, a few good introductions may be this and especially that :
There are two basic ways to represent time. One way represents time in
human terms, referred to as human time, such as year, month, day,
hour, minute and second. The other way, machine time, measures time
continuously along a timeline from an origin, called the epoch, in
nanosecond resolution. The Date-Time package provides a rich array of
classes for representing date and time. Some classes in the Date-Time
API are intended to represent machine time, and others are more suited
to representing human time.
I just want to subtract 1 hour from a DateTime I tried looking it up on Google and I found that there is a method called minus that takes a copy of the date and take a specific duration right here: http://www.joda.org/joda-time/apidocs/org/joda/time/DateTime.html#minus(long)
But I don't know how to use it and I can't an find a example on the internet.
Here's my code:
String string1 = (String) table_4.getValueAt(0, 1);
String string2= (String) table_4.getValueAt(0, 2);
DateTimeFormatter dtf = DateTimeFormat.forPattern("hh:mm a").withLocale(Locale.ENGLISH);
DateTime dateTime1 = dtf.parseDateTime(string1.toString());
DateTime dateTime2 = dtf.parseDateTime(string2.toString());
final String oldf = ("hh:mm a");
final String newf= ("hh.mm 0");
final String newf2= ("hh.mm a");
final String elapsedformat = ("hh.mm");
SimpleDateFormat format2 = new SimpleDateFormat(oldf);
SimpleDateFormat format2E = new SimpleDateFormat(newf);
Period timePeriod = new Period(dateTime1, dateTime2);
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendHours().appendSuffix(".")
.appendMinutes().appendSuffix("")
.toFormatter();
String elapsed = formatter.print(timePeriod);
table_4.setValueAt(elapsed,0,3);
DecimalFormat df = new DecimalFormat("00.00");
System.out.println(dateTime1);
table_4.setValueAt("", 0, 4);
table_4.setValueAt("", 0, 5);
Sample Data:
dateTime1: 08:00 AM
dateTime2: 05:00 PM
the period will be 9 hours. but i want it to be 8 hrs only because i want to subtract the lunch break in my program.
i tried it with this stupid code:
dateTime1.minus(-1)
I also tried parsing string1 to double so I can subtract it by one.
double strindtoD = Integer.parseInt(string1);
I also tried making another DateTime and use period to get the difference of the two time
String stringOneHour = ("01:00 AM");
DateTime dateTime3 = dtf.parseDateTime(stringOneHour.toString());
Period timePeriod = new Period(dateTime3, dateTime1);
Just use:
dateTime.minusHours(1)
This is documented in the API.
Note that DateTime objects are immutable, so the operation alone has no effect. You need to assign the result of this method to a new object (or replace itself):
dateTime = dateTime.minusHours(1);
As to how to obtain a Period out of the difference between two DateTimes, you must first go through an Interval:
Period period = new Interval(begin, end).toPeriod();
Link to a SO post explaining why there is both Period and Interval.
Side note: Joda Time uses a LOT of indirections in its API; as such reading the Javadoc not only requires one to read the methods for one class, but also look at the list of inherited methods from all the inherited abstract classes/interfaces; for instance, a DateTime is also a ReadableInstant. One you get used to it, though, it's a breeze.
If you are using an older version of org.joda.time.DateTime then you can use minus(ReadablePeriod period) method like this
Date date = LocalDate.now().minus(new Period(1, 0, 0, 0)).toDate();
where Period accepts int hours, int minutes, int seconds, int millis parameters
By using Calender class object you can use this method to subtract hours.
cal.add(Calendar.HOUR_OF_DAY, -numberOfHours);
and also here is complete example link
I have this time:
String myTime = "14:10";
Now I want to add 10 minutes to this time, so that it would be 14:20
How can I achieve this?
Something like this
String myTime = "14:10";
SimpleDateFormat df = new SimpleDateFormat("HH:mm");
Date d = df.parse(myTime);
Calendar cal = Calendar.getInstance();
cal.setTime(d);
cal.add(Calendar.MINUTE, 10);
String newTime = df.format(cal.getTime());
As a fair warning there might be some problems if daylight savings time is involved in this 10 minute period.
I would use Joda Time, parse the time as a LocalTime, and then use
time = time.plusMinutes(10);
Short but complete program to demonstrate this:
import org.joda.time.*;
import org.joda.time.format.*;
public class Test {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormat.forPattern("HH:mm");
LocalTime time = formatter.parseLocalTime("14:10");
time = time.plusMinutes(10);
System.out.println(formatter.print(time));
}
}
Note that I would definitely use Joda Time instead of java.util.Date/Calendar if you possibly can - it's a much nicer API.
Use Calendar.add(int field,int amount) method.
Java 7 Time API
DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm");
LocalTime lt = LocalTime.parse("14:10");
System.out.println(df.format(lt.plusMinutes(10)));
You need to have it converted to a Date, where you can then add a number of seconds, and convert it back to a string.
I used the code below to add a certain time interval to the current time.
int interval = 30;
SimpleDateFormat df = new SimpleDateFormat("HH:mm");
Calendar time = Calendar.getInstance();
Log.i("Time ", String.valueOf(df.format(time.getTime())));
time.add(Calendar.MINUTE, interval);
Log.i("New Time ", String.valueOf(df.format(time.getTime())));
You have a plenty of easy approaches within above answers.
This is just another idea. You can convert it to millisecond and add the TimeZoneOffset and add / deduct the mins/hours/days etc by milliseconds.
String myTime = "14:10";
int minsToAdd = 10;
Date date = new Date();
date.setTime((((Integer.parseInt(myTime.split(":")[0]))*60 + (Integer.parseInt(myTime.split(":")[1])))+ date1.getTimezoneOffset())*60000);
System.out.println(date.getHours() + ":"+date.getMinutes());
date.setTime(date.getTime()+ minsToAdd *60000);
System.out.println(date.getHours() + ":"+date.getMinutes());
Output :
14:10
14:20
I would recommend storing the time as integers and regulate it through the division and modulo operators, once that is done convert the integers into the string format you require.
I need to get the number of minutes between two dates. I know Joda is the best to use, but this is for an Android project, so I prefer to use a little external libraries as possible, and the app I'm building doesn't require the calculation to be surgically precise.
However, the code I'm using doesn't seem to be working. I'm trying to get the number of minutes between "11/21/2011 7:00:00 AM" and "11/21/2011 1:00:00 PM" (which should be 360 minutes), but the code I'm using returns 0:
int diff = minutesDiff(GetItemDate("11/21/2011 7:00:00 AM"), GetItemDate("11/21/2011 1:00:00 PM"));
public static Date GetItemDate(final String date)
{
final Calendar cal = Calendar.getInstance(TimeZone.getDefault());
final SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a");
format.setCalendar(cal);
try {
return format.parse(date);
} catch (ParseException e) {
return null;
}
}
public static int minutesDiff(Date earlierDate, Date laterDate)
{
if( earlierDate == null || laterDate == null ) return 0;
return (int)((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
}
If your GetItemDate is failing for either date, you will get zero. On the catch statement, place a println or debug to output the issue and see if that tells you something.
Also, just as a matter of practice, I'd change:
return (int)((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
to:
long result = ((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
return (int) result;
This gives you the opportunity to view the result of the math in an IDE.
I debugged through your code: there is ParseException in GetItemDate() for both of the date strings like:
Unparseable date: 11/21/2011 07:00:00 AM
The problem is that parsing AM/PM hours only works with "hh" (small caps!) or "KK". At least that is the case in my phone (it seems some of us didn't see this issue at all). I tested it also works with a single "h" too.
hh = 1-12
KK = 0-11
HH = 0-23
kk = 1-24
Change your SimpleDateFormat line to this:
final SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a", Locale.US);
This post explains the "a" and Locale: Unable to parse DateTime-string with AM/PM marker
PS. I'm from Finland so I must use the "Locale.US" part for this to work. US residents may test the code without it, I think.