I wanted to do a date range search in java suppose I wanted to search from 10-22-2019 to the present date.
But the question is to do the date range search in the chunk size of two weeks(consider this can vary but in form weeks) for eg here start date will 10-22-2019 but the end date will start date + 2 weeks added to it after the date range search is done for this and taking the result. Now the new start date should be were the previous date range search ended. and the end date should be now 2 weeks from the new start date again the search and this keeps on until I get till the present date.
public static IEnumerable<Tuple<DateTime, DateTime>> SplitDateRange(DateTime start, DateTime end, int dayChunkSize)
{
DateTime chunkEnd;
while ((chunkEnd = start.AddDays(dayChunkSize)) < end)
{
yield return Tuple.Create(start, chunkEnd);
start = chunkEnd;
}
yield return Tuple.Create(start, end);
}
Got this from one of the answers but have trouble in implementing in my situtation.
Simple iterative solution :
LocalDate start = LocalDate.parse("2019-10-22");
LocalDate end = LocalDate.now();
LocalDate chunckStart = start;
while (chunckStart.plusDays(15).isBefore(end)) {
doTheThing(chunckStart, chunckStart.plusDays(15));
chunckStart = chunckStart.plusDays(16);
}
doTheThing(chunckStart, end);
You can try it here.
try:
public static Iterator<Pair<LocalDate, LocalDate>> splitDataRange(LocalDate start, LocalDate end, int dayChunkSize) {
return new Iterator<Pair<LocalDate, LocalDate>>() {
private LocalDate chunkStart = start;
private LocalDate chunkEnd = start.plusDays(dayChunkSize);
#Override
public boolean hasNext() {
return end.compareTo(chunkEnd) > 0;
}
#Override
public Pair<LocalDate, LocalDate> next() {
Pair<LocalDate, LocalDate> chunk = new Pair<>(chunkStart, chunkEnd);
chunkStart = chunkEnd;
chunkEnd = chunkEnd.plusDays(dayChunkSize);
return chunk;
}
};
}
public static void main(String[] args) {
Iterator<Pair<LocalDate, LocalDate>> periodIterator = splitDataRange(LocalDate.of(2019, 3, 1),
LocalDate.of(2019, 5, 1), 20);
while (periodIterator.hasNext()) {
Pair<LocalDate, LocalDate> startEnd = periodIterator.next();
System.out.println(String.format("from %s to %s"
, startEnd.getValue0(), startEnd.getValue1()));
}
}
The Pair api is from:
<dependency>
<groupId>org.javatuples</groupId>
<artifactId>javatuples</artifactId>
<version>1.2</version>
</dependency>
Here's a solution using Streams and LocalDate:
LocalDate start = LocalDate.of(2020, 2, 28);
LocalDate end = LocalDate.now();
int step = 7;
start
.datesUntil(end, Period.ofDays(step))
.map(date -> {
LocalDate proposedEnd = date.plusDays(step);
LocalDate chunkEnd = proposedEnd.compareTo(end) > 0 ? end : proposedEnd;
return new SimpleEntry<>(date, chunkEnd);
})
.forEach(chunk -> System.out.println(chunk.getKey() + " until " + chunk.getValue()));
It generates the same output as the corresponding C# program.
The datesUntil method requires Java 9. Otherwise, if you're using Java 8, then you could use a helper method instead:
public static Stream<LocalDate> datesUntil(LocalDate from, LocalDate toExclusive) {
long daysBetween = ChronoUnit.DAYS.between(from, toExclusive);
return Stream.iterate(from, t -> t.plusDays(1))
.limit(daysBetween);
}
Related
I have a code that supports only API Level >= 26 in android:
public static String in = "7:00:00";
public static String in_until = "11:50:00";
public static String breakout_out = "11:51:00";
public static String breakout_out_until = "12:50:00";
public static String breakout_in = "12:51:00";
public static String breakout_in_until = "13:10:00";
public static String out = "16:50";
public static String getCurrentTimeLogType() {
// LocalTime target = LocalTime.parse( DataHandler.timestamp().split(" ")[1] ) ;
LocalTime target = LocalTime.parse("7:30:00") ;
if (target.isBefore(in) || (target.isAfter(in) && target.isBefore(in_until)))
return "TIME-IN";
else if (target.isAfter(breakout_out) && target.isBefore(breakout_out_until))
return "BREAK-OUT";
else if (target.isAfter(breakout_in) && target.isBefore(breakout_in_until))
return "BREAK IN";
else if (target.isAfter(out))
return "TIME-OUT";
return "UNKNOWN!";
}
I want to return if the specified time in the variables is within the current time to return what type of timestamp to add to database.
For example if today is 12:05 PM:
if (12:05 >= breakout_out && 12:05 <= breakout_out_until)
return "BREAK-OUT"
I want to achieve something like this. How can I achieve a code like this without using the unsupported LocalTime module?
What about something like below. Not tested though.
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Date breakout_out = sdf.parse("11:51:00");
Date breakout_out_until = sdf.parse("13:10:00");
Date current_time = sdf.parse("12.05.00");
if(current_time.before(breakout_out_until) && current_time.after(breakout_out)) {
return "BREAK-OUT"
}
I want to group some accounts by month, can i do this with Realm.io?
public class Account extends RealmObject {
.....
private Date date;
}
RealmResults accounts = realm.where(Account.class)
.beginGroup()
.equalTo("date", "MONTH(date)")//<----- wrong code
.endGroup()
.findAll();
thanks
Realm doesn't support GroupBy yet. Also be aware that beginGroup() is actually the same as parentheses. So your query is actually interpreted as :
// SQL pseudo code
SELECT * FROM Account WHERE (date = MONTH(date))
In Realm you would have to do something like this to select a single month:
// Between is [ monthStart, monthEnd ]
Date monthStart = new GregorianCalendar(2015, 5, 1).getTime();
Date monthEnd = new GregorianCalendar(2015, 6, 1).getTime() - 1;
accounts = realm.where(Account.class).between("date", monthStart, monthEnd).findAll();
or something like this to detect when a month changes
// pseudo code. You might want to use Calendar instead
accounts = realm.where(Account.class).findAllSorted("date")
Iterator<Account> it = accounts.iterator();
int previousMonth = it.next().getDate().getMonth();
while (it.hasNext) {
int month = it.next().getDate().getMonth();
if (month != previousMonth) {
// month changed
}
previousMonth = month;
}
I`m trying to build formatter in JodaTime to parse Period from strings like these:
year 1hour 90min
1year -60days 800min
1year +1months -1days +1hour -30min
I know I can build parser with PeriodFormatterBuilder in jodatime but with it I can`t parse first two examples
PeriodFormatter formatter = new PeriodFormatterBuilder()
.appendYears().appendSuffix("year", "years").appendSeparatorIfFieldsAfter(" ")
.appendMonths().appendSuffix("month", "months").appendSeparatorIfFieldsAfter(" ")
.appendDays().appendSuffix("day", "days").appendSeparatorIfFieldsAfter(" ")
.appendHours().appendSuffix("hour", "hours").appendSeparatorIfFieldsAfter(" ")
.appendMinutes().appendSuffix("min", "mins").appendSeparatorIfFieldsAfter(" ")
.appendSeconds().appendSuffix("sec", "secs")
.toFormatter();
Is there any way I can tell joda that tose fields are optional?
If you really wanna achieve this, you can do so by writing a custom parser. For this you will have to implement PeriodParser class and implement the parseInto() method.
#Override
public int parseInto(ReadWritablePeriod period, String periodStr,
int position, Locale locale) {
String tokens[] = periodStr.split(" ");
period.addYears(0);
period.addMonths(0);
period.addDays(0);
period.addHours(0);
period.addMinutes(0);
period.addSeconds(0);
for (String token : tokens) {
int count = 0;
if (token.contains("year")) {
String years = token.substring(0, token.indexOf("year"));
period.addYears(years.length() > 0 ? Integer.valueOf(years) : 0);
continue;
}
if (token.contains("hour")) {
period.addHours(Integer.valueOf(token.substring(0, token.indexOf("hour"))));
continue;
}
if (token.contains("min")) {
period.addMinutes(Integer.valueOf(token.substring(0, token.indexOf("min"))));
continue;
}
if (token.contains("months")) {
period.addMonths(Integer.valueOf(token.substring(0, token.indexOf("months"))));
continue;
}
if (token.contains("day")) {
period.addDays(Integer.valueOf(token.substring(0, token.indexOf("days"))));
continue;
}
}
return periodStr.length();
}
After that use the following code to create a formatter and parse the period.
PeriodFormatterBuilder builder = new PeriodFormatterBuilder();
PeriodFormatter formatter = builder.append(null, new MyParsePeriod()).toFormatter();
I need a timezone display values as follows :
(UTC + 05:30) Chennai, Kolkata, Mumbai, New Delhi
But by using following method I am getting bit different output. How should I get the timezone display name as above ? (if required, I can use JODA).
public class TimeZoneUtil {
private static final String TIMEZONE_ID_PREFIXES =
"^(Africa|America|Asia|Atlantic|Australia|Europe|Indian|Pacific)/.*";
private static List<TimeZone> timeZones;
public static List<TimeZone> getTimeZones() {
if (timeZones == null) {
timeZones = new ArrayList<TimeZone>();
final String[] timeZoneIds = TimeZone.getAvailableIDs();
for (final String id : timeZoneIds) {
if (id.matches(TIMEZONE_ID_PREFIXES)) {
timeZones.add(TimeZone.getTimeZone(id));
}
}
Collections.sort(timeZones, new Comparator<TimeZone>() {
public int compare(final TimeZone t1, final TimeZone t2) {
return t1.getID().compareTo(t2.getID());
}
});
}
return timeZones;
}
public static String getName(TimeZone timeZone) {
return timeZone.getID().replaceAll("_", " ") + " - " + timeZone.getDisplayName();
}
public static void main(String[] args) {
timeZones = getTimeZones();
for (TimeZone timeZone : timeZones) {
System.out.println(getName(timeZone));
}
}
}
This code may do the trick for you:
public static void main(String[] args) {
for (String timeZoneId: TimeZone.getAvailableIDs()) {
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
// Filter out timezone IDs such as "GMT+3"; more thorough filtering is required though
if (!timeZoneId.matches(".*/.*")) {
continue;
}
String region = timeZoneId.replaceAll(".*/", "").replaceAll("_", " ");
int hours = Math.abs(timeZone.getRawOffset()) / 3600000;
int minutes = Math.abs(timeZone.getRawOffset() / 60000) % 60;
String sign = timeZone.getRawOffset() >= 0 ? "+" : "-";
String timeZonePretty = String.format("(UTC %s %02d:%02d) %s", sign, hours, minutes, region);
System.out.println(timeZonePretty);
}
}
The output looks like this:
(UTC + 09:00) Tokyo
There are, however, a few caveats:
I only filter out timezones whose ID matches the format "continent/region" (e.g. "America/New_York"). You would have to do a more thorough filtering process to get rid of outputs such as (UTC - 08:00) GMT+8 though.
You should read the documentation for TimeZone.getRawOffSet() and understand what it's doing. For example, it doesn't DST effects into consideration.
On the whole, you should know that this is a messy approach, primarily because the timezone ID can be of so many different formats. Maybe you could restrict yourself down to the timezones that matter for your application, and just have a key value mapping of timezone IDs to display names?
All,
I am in the process or rewriting some code that I wrote a while back. The objective of the code was to calcualte a date and time based on a string in the following formats:
DayStart+2Hour+1Day-2Minutes
NOW+20Day
MonthStart+1Month
Which would take the start of the day (in local time), e.g. 2011-09-15 00:00:00 BST (2011-09-15 23:00 GMT) then add 2 hours, add 1 day, and subtract 2 minutes.
The implementation is in Java and the original algorithm was pretty basic. It iterated through each character in the string and appended to a buffer. The buffer was then checked to see if it ended with the strings I was looking (date specifier e.g MINUTE, HOUR, DAYSTART, etc.) for then extracted the number and added to an ArrayList where DateOffset was a simple class with a int and String which was date specifier. Here is some sample code:
// hard coded for sample
String s = "DayStart+2Hour+1Day-2Minutes";
StringBuilder sbBuffer = new StringBuilder();
String buffer;
// iterate through date string
for (char c : s.toCharArray()) {
sbBuffer.append(c);
buffer = sbBuffer.toString();
// check to see the end of the buffer string is what we expect
if (buffer.endsWith("DAYSTART")) {
offsets.add(new DateOffset(0, "DAYSTART"));
sbBuffer = new StringBuilder();
} else if (buffer.endsWith("DAY") && buffer.length() > 3) {
String numberStringPart = buffer.substring(0, buffer.length() - 3);
numberStringPart = numberStringPart.replaceAll("[+]", "").trim(); // need as parseInt does not like the +.
offsets.add(new DateOffset(Integer.parseInt(numberStringPart), "DAY"));
sbBuffer = new StringBuilder();
} ... and so on ...
else {
}
}
After the string was parsed I iterated through ArrayList to calculate my datetime.
The problem with the above is probably not efficient although we have experienced no problems. It also does not pick up any errors so you could enter DayStart+2GKGKER.
I'm just trying to come up with some fresh and neat ideas on what to use to rewrite it. I have done a little regex but not too sure if this would be the best route.
Any thoughts?
Thanks,
Andez
Define a grammar for your expressions. Take a look at the ANTLR framework to help you construct a grammar and process your expressions.
Woohoo, that was fun! Thank you! :-)
public class DateExpressions {
private Map<String, Date> dateVariables;
private Map<String, Integer> temporalUnits;
private Map<Character, Integer> temporalOperations;
public static DateExpressions createInstance() {
DateExpressions de = new DateExpressions();
Calendar c = Calendar.getInstance();
de.setVariable("NOW", c.getTime());
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
de.setVariable("DayStart", c.getTime());
c.set(Calendar.DAY_OF_MONTH, 1);
de.setVariable("MonthStart", c.getTime());
return de;
}
public DateExpressions() {
this.dateVariables = new HashMap<String, Date>();
this.temporalUnits = new HashMap<String, Integer>();
this.temporalUnits.put("Second", Calendar.SECOND);
this.temporalUnits.put("Minute", Calendar.MINUTE);
this.temporalUnits.put("Hour", Calendar.HOUR_OF_DAY);
this.temporalUnits.put("Day", Calendar.DATE);
this.temporalUnits.put("Month", Calendar.MONTH);
this.temporalUnits.put("Year", Calendar.YEAR);
this.temporalOperations = new HashMap<Character, Integer>();
this.temporalOperations.put('+', 1);
this.temporalOperations.put('-', -1);
}
public void setVariable(String key, Date value) {
this.dateVariables.put(key, value);
}
public Date parseExpression(String expr) throws IOException {
StringReader sr = new StringReader(expr);
String s;
int n;
char c;
int offset;
int unit;
int op = 1;
Calendar base = null;
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
while ((n = sr.read()) != -1) {
c = (char) n;
if (base == null && temporalOperations.containsKey(c)) {
s = sb2.toString();
if (!dateVariables.containsKey(s)) {
throw new IOException("Unknown variable '" + s + "' used");
}
base = Calendar.getInstance();
base.setTime(dateVariables.get(sb2.toString()));
op = temporalOperations.get(c);
sb1.setLength(0);
sb2.setLength(0);
} else if (temporalOperations.containsKey(c)) {
if (!temporalUnits.containsKey(sb2.toString())) {
throw new IOException(
"Parse error: unknown temporal unit used '"
+ sb2.toString() + "'");
}
offset = Integer.parseInt(sb1.toString());
unit = temporalUnits.get(sb2.toString());
base.add(unit, op * offset);
op = temporalOperations.get(c);
sb1.setLength(0);
sb2.setLength(0);
} else if (Character.isDigit(c)) {
sb1.append(c);
} else {
sb2.append(c);
}
}
if (!temporalUnits.containsKey(sb2.toString())) {
throw new IOException("Parse error: unknown temporal unit used '"
+ sb2.toString() + "'");
}
offset = Integer.parseInt(sb1.toString());
unit = temporalUnits.get(sb2.toString());
base.add(unit, op * offset);
return base.getTime();
}
public static void main(String[] args) throws IOException {
DateExpressions de = DateExpressions.createInstance();
System.out.println(de.parseExpression("DayStart+2Hour+1Day-2Minute"));
System.out.println(de.parseExpression("NOW+20Day"));
System.out.println(de.parseExpression("MonthStart+1Month"));
}
}
If you're after rapid experimentation, sometimes a literate API combined with on the fly compilation is an easy way to go.
So, your example could look like (given appropriate static imports)
daystart().plus()
.hours(2).plus()
.days(1).minutes(2)
or even (given milliseconds as the basic units)
daystart() + hours(2) + days(1) - minutes(2)
Regex seems to be the best bet for such a scenario. Although, I'm puzzled why would you want to interpret strings in this manner, rather than having sophisticated APIs.