diff --git a/xchart-examples/src/main/java/com/xeiam/xchart/demo/charts/Example4.java b/xchart-examples/src/main/java/com/xeiam/xchart/demo/charts/Example4.java index 7c03d3526c88ddb7f530b2e3d6c50cb7b38e2a9d..433e9bf19fcab863d14b20abe21c8abdefd54c66 100644 --- a/xchart-examples/src/main/java/com/xeiam/xchart/demo/charts/Example4.java +++ b/xchart-examples/src/main/java/com/xeiam/xchart/demo/charts/Example4.java @@ -21,6 +21,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.TimeZone; import com.xeiam.xchart.Chart; import com.xeiam.xchart.Series; @@ -67,6 +68,7 @@ public class Example4 implements ExampleChart { chart.setTitle("Example4"); chart.setXAxisTitle("time of day"); chart.setYAxisTitle("gigawatts"); + chart.setTimezone(TimeZone.getTimeZone("UTC")); Series series = chart.addDateSeries("value", xData, yData); diff --git a/xchart/src/main/java/com/xeiam/xchart/Chart.java b/xchart/src/main/java/com/xeiam/xchart/Chart.java index fc76c8b4067ba8aee7af2fc9b2d22ddcaa4b7362..9d2edcbc0748cd7e349e09768dc232b64ab3cee5 100644 --- a/xchart/src/main/java/com/xeiam/xchart/Chart.java +++ b/xchart/src/main/java/com/xeiam/xchart/Chart.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Locale; +import java.util.TimeZone; import com.xeiam.xchart.internal.chartpart.AxisPair; import com.xeiam.xchart.internal.chartpart.ChartTitle; @@ -462,7 +463,7 @@ public class Chart { /** * Set the locale to use for rendering the chart * - * @param locale - the locale to use when drawing the chart + * @param locale - the locale to use when formatting Strings and dates for the axis tick labels */ public void setLocale(Locale locale) { @@ -470,4 +471,15 @@ public class Chart { this.axisPair.yAxis.axisTick.locale = locale; } + /** + * Set the timezone to use for formatting Date axis tick labels + * + * @param timezone the timezone to use when formatting date data + */ + public void setTimezone(TimeZone timezone) { + + this.axisPair.xAxis.axisTick.timezone = timezone; + this.axisPair.yAxis.axisTick.timezone = timezone; + } + } diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java index dd2f5a2c6aae981f4bd766939e9f28810329a43f..69689e57aa1fe71f064f40c64b22f6d0281671ec 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java @@ -21,6 +21,7 @@ import java.math.BigDecimal; import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.TimeZone; import com.xeiam.xchart.internal.chartpart.Axis.AxisType; import com.xeiam.xchart.internal.chartpart.Axis.Direction; @@ -59,9 +60,12 @@ public class AxisTick implements IChartPart, IHideable { private int workingSpace; - /** the Locale for Date tick labels */ + /** the Locale for tick labels */ public Locale locale; + /** the TimeZone for Date tick labels */ + public TimeZone timezone; + public String normalDecimalPattern = null; public String scientificDecimalPattern = null; public String datePattern = null; @@ -254,7 +258,7 @@ public class AxisTick implements IChartPart, IHideable { } else { - return AxisValueFormatterUtil.formatDateValue(value, axis.min, axis.max, datePattern, locale); + return AxisValueFormatterUtil.formatDateValue(value, axis.min, axis.max, datePattern, locale, timezone); } } diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/misc/AxisValueFormatterUtil.java b/xchart/src/main/java/com/xeiam/xchart/internal/misc/AxisValueFormatterUtil.java index 1a6c184ad4d636a5915bde6a6fb93fb6bf64cbc1..554adf9fade8cefea3b3b48867b69e8eb5522f42 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/misc/AxisValueFormatterUtil.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/misc/AxisValueFormatterUtil.java @@ -26,6 +26,8 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Locale; +import java.util.TimeZone; +import java.util.concurrent.TimeUnit; /** * @author timmolter @@ -36,14 +38,15 @@ public class AxisValueFormatterUtil { private static final String SCIENTIFIC_DECIMAL_PATTERN = "0.##E0"; private static final String DATE_PATTERN = "HHmmss"; private static final Locale LOCALE = Locale.getDefault(); + private static final TimeZone TIMEZONE = TimeZone.getDefault(); - private static final BigDecimal SEC_SCALE = new BigDecimal(1000L); - private static final BigDecimal MIN_SCALE = new BigDecimal(1000L * 60); - private static final BigDecimal HOUR_SCALE = new BigDecimal(1000L * 60 * 60); - private static final BigDecimal DAY_SCALE = new BigDecimal(1000L * 60 * 60 * 24); - private static final BigDecimal WEEK_SCALE = new BigDecimal(1000L * 60 * 60 * 24 * 7); - private static final BigDecimal MONTH_SCALE = new BigDecimal(1000L * 60 * 60 * 24 * 31); - private static final BigDecimal YEAR_SCALE = new BigDecimal(1000L * 60 * 60 * 24 * 365); + private static final long SEC_SCALE = TimeUnit.SECONDS.toMillis(1L); + private static final long MIN_SCALE = TimeUnit.MINUTES.toMillis(1L); + private static final long HOUR_SCALE = TimeUnit.HOURS.toMillis(1L); + private static final long DAY_SCALE = TimeUnit.DAYS.toMillis(1L); + private static final long WEEK_SCALE = TimeUnit.DAYS.toMillis(1L) * 7; + private static final long MONTH_SCALE = TimeUnit.DAYS.toMillis(1L) * 31; + private static final long YEAR_SCALE = TimeUnit.DAYS.toMillis(1L) * 365; /** * Constructor @@ -93,27 +96,27 @@ public class AxisValueFormatterUtil { * @param localeOverride * @return the formatted date value as a String */ - public static String formatDateValue(BigDecimal value, BigDecimal min, BigDecimal max, String datePatternOverride, Locale localeOverride) { + public static String formatDateValue(BigDecimal value, BigDecimal min, BigDecimal max, String datePatternOverride, Locale localeOverride, TimeZone timeZoneOverride) { // intelligently set datepattern if none is given String datePattern = datePatternOverride; if (datePatternOverride == null) { datePattern = DATE_PATTERN; - BigDecimal diff = max.subtract(min); + long diff = max.subtract(min).longValue(); - if (diff.compareTo(SEC_SCALE) == -1) { + if (diff < SEC_SCALE) { datePattern = "ss:S"; - } else if (diff.compareTo(MIN_SCALE) == -1) { + } else if (diff < MIN_SCALE) { datePattern = "mm:ss"; - } else if (diff.compareTo(HOUR_SCALE) == -1) { + } else if (diff < HOUR_SCALE) { datePattern = "HH:mm"; - } else if (diff.compareTo(DAY_SCALE) == -1) { - datePattern = "dd:HH"; - } else if (diff.compareTo(WEEK_SCALE) == -1) { + } else if (diff < DAY_SCALE) { + datePattern = "EEE HH:mm"; + } else if (diff < WEEK_SCALE) { datePattern = "EEE"; - } else if (diff.compareTo(MONTH_SCALE) == -1) { + } else if (diff < MONTH_SCALE) { datePattern = "MMM-dd"; - } else if (diff.compareTo(YEAR_SCALE) == -1) { + } else if (diff < YEAR_SCALE) { datePattern = "yyyy:MMM"; } else { datePattern = "yyyy"; @@ -122,9 +125,9 @@ public class AxisValueFormatterUtil { } SimpleDateFormat simpleDateformat = new SimpleDateFormat(datePattern, localeOverride == null ? LOCALE : localeOverride); + simpleDateformat.setTimeZone(timeZoneOverride == null ? TIMEZONE : timeZoneOverride); simpleDateformat.applyPattern(datePattern); return simpleDateformat.format(value.longValueExact()); } - } diff --git a/xchart/src/test/java/com/xeiam/xchart/ValueFormatTest.java b/xchart/src/test/java/com/xeiam/xchart/ValueFormatTest.java index c8a99093b50d875526bc64615d417ca38a0c2bac..b19195468a48fe11c5c3cb1950301568080bfe69 100644 --- a/xchart/src/test/java/com/xeiam/xchart/ValueFormatTest.java +++ b/xchart/src/test/java/com/xeiam/xchart/ValueFormatTest.java @@ -26,6 +26,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import java.math.BigDecimal; import java.util.Locale; +import java.util.TimeZone; import org.junit.Test; @@ -36,9 +37,6 @@ import com.xeiam.xchart.internal.misc.AxisValueFormatterUtil; */ public class ValueFormatTest { - // private final String normalDecimalPattern = "#.####"; - // private final String scientificDecimalPattern = "0.##E0"; - // private final String datePattern = "HHmmss"; private final Locale locale = Locale.US; @Test @@ -115,61 +113,62 @@ public class ValueFormatTest { @Test public void testDateFormatting() { + TimeZone timeZone = TimeZone.getTimeZone("UTC"); + // ms BigDecimal value = new BigDecimal(1358108105531L); BigDecimal min = new BigDecimal(1358108105100L); BigDecimal max = new BigDecimal(1358108105900L); - String stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale); + String stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale, timeZone); assertThat(stringValue, equalTo("05:531")); // sec value = new BigDecimal(1358108105000L); min = new BigDecimal(1358108101000L); max = new BigDecimal(1358108109000L); - stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale); + stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale, timeZone); assertThat(stringValue, equalTo("15:05")); - // TODO this fails on a server in a different timezone. how to fix? - // // min - // value = new BigDecimal(1358111750000L); - // min = new BigDecimal(1358111690000L); - // max = new BigDecimal(1358111870000L); - // stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale); - // assertThat(stringValue, equalTo("22:15")); - // - // // hour - // value = new BigDecimal(1358111870000L); - // min = new BigDecimal(1358101070000L); - // max = new BigDecimal(1358115470000L); - // stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale); - // assertThat(stringValue, equalTo("13:22")); + // min + value = new BigDecimal(1358111750000L); + min = new BigDecimal(1358111690000L); + max = new BigDecimal(1358111870000L); + stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale, timeZone); + assertThat(stringValue, equalTo("21:15")); + + // hour + value = new BigDecimal(1358111870000L); + min = new BigDecimal(1358101070000L); + max = new BigDecimal(1358115470000L); + stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale, timeZone); + assertThat(stringValue, equalTo("Sun 21:17")); // day value = new BigDecimal(1358112317000L); min = new BigDecimal(1357939517000L); max = new BigDecimal(1358285117000L); - stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale); + stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale, timeZone); assertThat(stringValue, equalTo("Sun")); // week value = new BigDecimal(1358112317000L); min = new BigDecimal(1357075517000L); max = new BigDecimal(1359149117000L); - stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale); + stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale, timeZone); assertThat(stringValue, equalTo("Jan-13")); // month value = new BigDecimal(1358112838000L); min = new BigDecimal(1354397638000L); max = new BigDecimal(1361223238000L); - stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale); + stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale, timeZone); assertThat(stringValue, equalTo("2013:Jan")); // year value = new BigDecimal(1358113402000L); min = new BigDecimal(1263419002000L); max = new BigDecimal(1421185402000L); - stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale); + stringValue = AxisValueFormatterUtil.formatDateValue(value, min, max, null, locale, timeZone); assertThat(stringValue, equalTo("2013")); }