Time formatter utilities
This commit is contained in:
parent
a76d5cb1ac
commit
0373867875
|
@ -99,5 +99,6 @@
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
|
||||||
<classpathentry kind="output" path="target/classes"/>
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|
|
@ -215,8 +215,6 @@ public class RecipeDetailBean implements Serializable {
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
private void init() {
|
private void init() {
|
||||||
this.recipe = userSession.getRecipe();
|
this.recipe = userSession.getRecipe();
|
||||||
|
|
||||||
log.info("Using recipe: " + this.recipe);
|
|
||||||
/**
|
/**
|
||||||
* For "create new, this recipe is a blank constructed
|
* For "create new, this recipe is a blank constructed
|
||||||
* and passed from main page. For Detail display, it's
|
* and passed from main page. For Detail display, it's
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.mousetech.gourmetj.persistence.model.Category;
|
import com.mousetech.gourmetj.persistence.model.Category;
|
||||||
import com.mousetech.gourmetj.persistence.model.Recipe;
|
import com.mousetech.gourmetj.persistence.model.Recipe;
|
||||||
|
import com.mousetech.gourmetj.utils.TimeFormatter;
|
||||||
|
|
||||||
@Named
|
@Named
|
||||||
@SessionScoped
|
@SessionScoped
|
||||||
|
@ -123,45 +124,14 @@ public class UserSession implements Serializable {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//** Util, consider conversion to JSF Converter
|
||||||
public String formatTime(Long ltime) {
|
public String formatTime(Long ltime) {
|
||||||
if (ltime == null) {
|
return TimeFormatter.formatTime(ltime);
|
||||||
return "";
|
|
||||||
}
|
|
||||||
int time = ltime.intValue();
|
|
||||||
int dd, hh, mm, ss;
|
|
||||||
ss = time % 60;
|
|
||||||
time /= 60;
|
|
||||||
mm = time % 60;
|
|
||||||
time /= 60;
|
|
||||||
hh = time % 24;
|
|
||||||
dd = time / 24;
|
|
||||||
StringBuffer sb = new StringBuffer(20);
|
|
||||||
if (dd > 0) {
|
|
||||||
sb.append(dd).append("d ");
|
|
||||||
}
|
|
||||||
if (hh > 0) {
|
|
||||||
sb.append(hh).append("h ");
|
|
||||||
}
|
|
||||||
if (mm > 0) {
|
|
||||||
sb.append(mm);
|
|
||||||
if ((ss == 0) && (hh == 0)) {
|
|
||||||
sb.append(" minutes");
|
|
||||||
} else {
|
|
||||||
sb.append("min. ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ss > 0) {
|
|
||||||
sb.append(dd).append("sec. ");
|
|
||||||
}
|
|
||||||
return sb.toString().trim();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Primefaces handle session timeout
|
// Primefaces handle session timeout
|
||||||
|
// Session timeout, ms
|
||||||
/**
|
long sessionTimeoutInterval = 30000L;
|
||||||
* Session timeout, msec.
|
|
||||||
*/
|
|
||||||
private long sessionTimeoutInterval = 300000;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the sessionTimeoutInterval
|
* @return the sessionTimeoutInterval
|
||||||
|
@ -176,7 +146,8 @@ public class UserSession implements Serializable {
|
||||||
.executeScript("sessionExpiredConfirmation.show()");
|
.executeScript("sessionExpiredConfirmation.show()");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void logoutAction() {
|
public String logoutAction() {
|
||||||
log.warn("Session Idle listener logout");
|
log.warn("Session Idle listener logout");
|
||||||
|
return "/main.jsf";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
181
src/main/java/com/mousetech/gourmetj/utils/TimeFormatter.java
Normal file
181
src/main/java/com/mousetech/gourmetj/utils/TimeFormatter.java
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
package com.mousetech.gourmetj.utils;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle conversion of complex time fields where days, hours,
|
||||||
|
* minutes and seconds may be present as separate entities.
|
||||||
|
*
|
||||||
|
* @author timh
|
||||||
|
* @since Jan 8, 2022
|
||||||
|
*/
|
||||||
|
public class TimeFormatter {
|
||||||
|
|
||||||
|
/* Logger */
|
||||||
|
|
||||||
|
private static final Logger log =
|
||||||
|
LoggerFactory.getLogger(TimeFormatter.class);
|
||||||
|
|
||||||
|
public static String formatTime(Long ltime) {
|
||||||
|
if (ltime == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int time = ltime.intValue();
|
||||||
|
int dd, hh, mm, ss;
|
||||||
|
ss = time % 60;
|
||||||
|
time /= 60;
|
||||||
|
mm = time % 60;
|
||||||
|
time /= 60;
|
||||||
|
hh = time % 24;
|
||||||
|
dd = time / 24;
|
||||||
|
StringBuffer sb = new StringBuffer(20);
|
||||||
|
if (dd > 0) {
|
||||||
|
sb.append(dd).append("d ");
|
||||||
|
}
|
||||||
|
if (hh > 0) {
|
||||||
|
sb.append(hh).append("h ");
|
||||||
|
}
|
||||||
|
if (mm > 0) {
|
||||||
|
sb.append(mm);
|
||||||
|
if ((ss == 0) && (hh == 0)) {
|
||||||
|
sb.append(" minutes");
|
||||||
|
} else {
|
||||||
|
sb.append("min. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ss > 0) {
|
||||||
|
sb.append(dd).append("sec. ");
|
||||||
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// private enum MunchUnit {
|
||||||
|
// mu_NONE, mu_DAY, mu_HOUR, mu_MINUTE, mw_SECOND
|
||||||
|
// }
|
||||||
|
|
||||||
|
private static class TimeMuncher {
|
||||||
|
|
||||||
|
public class MunchException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
final private String SPAT_DAYS = "days?|d";
|
||||||
|
final private String SPAT_HOURS = "hours?|h|hr";
|
||||||
|
final private String SPAT_MINUTES = "minutes?|mins?|m";
|
||||||
|
final private String SPAT_SECONDS = "seconds?|secs?|s";
|
||||||
|
|
||||||
|
final Pattern pat_number;
|
||||||
|
final Pattern pat_days;
|
||||||
|
final Pattern pat_hours;
|
||||||
|
final Pattern pat_mins;
|
||||||
|
final Pattern pat_secs;
|
||||||
|
|
||||||
|
final Scanner scanner;
|
||||||
|
|
||||||
|
public TimeMuncher(String timestr) {
|
||||||
|
pat_number =
|
||||||
|
Pattern.compile("(\\d[\\,\\.]?\\d*)?(.*)");
|
||||||
|
// Compile here for future I18N support
|
||||||
|
pat_days = Pattern.compile(SPAT_DAYS);
|
||||||
|
pat_hours = Pattern.compile(SPAT_HOURS);
|
||||||
|
pat_mins = Pattern.compile(SPAT_MINUTES);
|
||||||
|
pat_secs = Pattern.compile(SPAT_SECONDS);
|
||||||
|
|
||||||
|
scanner = new Scanner(timestr);
|
||||||
|
scanner.useDelimiter("\\W");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long scan() {
|
||||||
|
Double sum = null;
|
||||||
|
Double dvalue = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (scanner.hasNext()) {
|
||||||
|
if (scanner.hasNextDouble()) {
|
||||||
|
dvalue = scanner.nextDouble();
|
||||||
|
} else {
|
||||||
|
String units = scanner.next();
|
||||||
|
sum = setSum(sum, dvalue, units);
|
||||||
|
dvalue = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (MunchException e) {
|
||||||
|
log.warn("Unparseable time value");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (sum == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return sum.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Double setSum(Double sum, Double dvalue,
|
||||||
|
String units) throws MunchException {
|
||||||
|
Matcher m;
|
||||||
|
|
||||||
|
m = pat_number.matcher(units);
|
||||||
|
|
||||||
|
if (!m.matches()) {
|
||||||
|
throw new MunchException();
|
||||||
|
}
|
||||||
|
if (m.group(1) != null) {
|
||||||
|
String a = m.group(1);
|
||||||
|
if (dvalue != null) {
|
||||||
|
throw new MunchException();
|
||||||
|
}
|
||||||
|
dvalue = Double
|
||||||
|
.valueOf(a);
|
||||||
|
//units = units.substring(m.end());
|
||||||
|
}
|
||||||
|
units = m.group(2);
|
||||||
|
m = pat_days.matcher(units);
|
||||||
|
if (m.matches()) {
|
||||||
|
return addToSum(sum, dvalue,
|
||||||
|
24L * 60L * 60L * 1000L);
|
||||||
|
}
|
||||||
|
m = pat_hours.matcher(units);
|
||||||
|
if (m.matches()) {
|
||||||
|
return addToSum(sum, dvalue, 60L * 60L * 1000L);
|
||||||
|
}
|
||||||
|
m = pat_mins.matcher(units);
|
||||||
|
if (m.matches()) {
|
||||||
|
return addToSum(sum, dvalue, 60L * 1000L);
|
||||||
|
}
|
||||||
|
m = pat_secs.matcher(units);
|
||||||
|
if (m.matches()) {
|
||||||
|
return addToSum(sum, dvalue, 1000L);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Double addToSum(Double sum, Double dvalue,
|
||||||
|
long l) throws MunchException {
|
||||||
|
if (dvalue == null) {
|
||||||
|
throw new TimeMuncher.MunchException();
|
||||||
|
}
|
||||||
|
dvalue *= l;
|
||||||
|
if (sum == null) {
|
||||||
|
sum = 0.0;
|
||||||
|
}
|
||||||
|
sum += dvalue;
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long parseTime(String timestr) {
|
||||||
|
TimeMuncher muncher = new TimeMuncher(timestr);
|
||||||
|
|
||||||
|
Long interval = muncher.scan();
|
||||||
|
return interval;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package com.mousetech.gourmetj.utils;
|
|
@ -40,16 +40,16 @@
|
||||||
</p:idleMonitor>
|
</p:idleMonitor>
|
||||||
<p:confirmDialog closable="false"
|
<p:confirmDialog closable="false"
|
||||||
id="sessionExpiredDlg"
|
id="sessionExpiredDlg"
|
||||||
message="Your session expired."
|
message="Your session has expired."
|
||||||
header="#{msgs['confirmDialog.initiatingDestroyProcess.label']}"
|
header="#{msgs['confirmDialog.initiatingDestroyProcess.label']}"
|
||||||
severity="alert"
|
severity="alert"
|
||||||
widgetVar="sessionExpiredConfirmation"
|
widgetVar="sessionExpiredConfirmation"
|
||||||
style="z-index: 25000"
|
style="z-index: 25000"
|
||||||
>
|
>
|
||||||
<p:commandButton id="confirmRouteDel"
|
<p:commandButton id="cmdExpiredOK"
|
||||||
value="Ok"
|
value="OK"
|
||||||
oncomplete="PF('sessionExpiredDlg').hide()"
|
action="/main.jsf"
|
||||||
actionListener="#{userSession.logoutAction}"
|
oncomplete="PF('sessionExpiredConfirmation').hide()"
|
||||||
/>
|
/>
|
||||||
</p:confirmDialog>
|
</p:confirmDialog>
|
||||||
</h:form>
|
</h:form>
|
||||||
|
|
|
@ -360,10 +360,12 @@
|
||||||
</p:tabView>
|
</p:tabView>
|
||||||
<p:commandButton id="doSave" value="Save"
|
<p:commandButton id="doSave" value="Save"
|
||||||
icon="ui-icon-pencil"
|
icon="ui-icon-pencil"
|
||||||
|
ajax="false"
|
||||||
disabled="{not recipeDetailBean.dirty}"
|
disabled="{not recipeDetailBean.dirty}"
|
||||||
action="#{recipeDetailBean.doSave}"
|
action="#{recipeDetailBean.doSave}"
|
||||||
/>
|
/>
|
||||||
<p:commandButton id="doCancel" value="Cancel"
|
<p:commandButton id="doCancel" value="Cancel"
|
||||||
|
ajax="false"
|
||||||
immediate="true" action="recipeDetails.jsf"
|
immediate="true" action="recipeDetails.jsf"
|
||||||
/>
|
/>
|
||||||
</h:form>
|
</h:form>
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<title>ERROR - Page Expired</title>
|
<title>ERROR - Page Expired</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Page Expired</h1>
|
<h1>Page Expired</h1>
|
||||||
<p>The page state could not be restored because it was left
|
<p>The page state could not be restored because it was
|
||||||
idle too long.</p>
|
left idle too long.</p>
|
||||||
<p><a href="/main.jsf">Return to Main Page</a></p>
|
<p>
|
||||||
|
<a href="/main.jsf">Return to Main Page</a>
|
||||||
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -45,12 +45,12 @@
|
||||||
columns="2"
|
columns="2"
|
||||||
>
|
>
|
||||||
<p:commandButton
|
<p:commandButton
|
||||||
value="Back"
|
value="Back" ajax="false"
|
||||||
icon="ui-icon-arrowthick-1-w"
|
icon="ui-icon-arrowthick-1-w"
|
||||||
action="main.jsf"
|
action="main.jsf"
|
||||||
immediate="true"
|
immediate="true"
|
||||||
/>
|
/>
|
||||||
<p:commandButton
|
<p:commandButton ajax="false"
|
||||||
value="Print"
|
value="Print"
|
||||||
icon="ui-icon-print"
|
icon="ui-icon-print"
|
||||||
action="recipePrint.jsf"
|
action="recipePrint.jsf"
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2022, Tim Holloway
|
||||||
|
*
|
||||||
|
* Date written: Jan 8, 2022
|
||||||
|
* Author: Tim Holloway <timh@mousetech.com>
|
||||||
|
*/
|
||||||
|
package com.mousetech.gourmetj.utils;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author timh
|
||||||
|
* @since Jan 8, 2022
|
||||||
|
*/
|
||||||
|
class TimeFormatterTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws java.lang.Exception
|
||||||
|
*/
|
||||||
|
@BeforeAll
|
||||||
|
static void setUpBeforeClass() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test() {
|
||||||
|
assertEquals(5000, TimeFormatter.parseTime("5s"));
|
||||||
|
assertEquals(5000*60, TimeFormatter.parseTime("5m"));
|
||||||
|
|
||||||
|
assertEquals(3600_000 + 25*60_000, TimeFormatter.parseTime("1 hour, 25 min"));
|
||||||
|
|
||||||
|
assertEquals(5*3600000 + 6*60000, TimeFormatter.parseTime("5h 6m"));
|
||||||
|
assertEquals(277562000L, TimeFormatter.parseTime("3d 5h 6m 2s"));
|
||||||
|
|
||||||
|
assertEquals(18000000L, TimeFormatter.parseTime("1.5 hours"));
|
||||||
|
|
||||||
|
assertEquals(3*3600_000, TimeFormatter.parseTime("3 hours"));
|
||||||
|
|
||||||
|
assertNull(TimeFormatter.parseTime("1 week"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user