Skip to content

Commit

Permalink
Refactor time related utility methods (#2164)
Browse files Browse the repository at this point in the history
PR #2113 exposed failures in tests of DefaultMailCreator class: createErrorEmail, createFirstErrorMessage and createSuccessEmail.

Failures were related to an early initialization of a static SimpleDateFormat object inside the class. As a result of this, changes to the default timezone made later in the tests did not have an effect on that object.

This PR solves this issue by eliminating the use of non-immutable static fields in the utility method that formats dates. It also moves time related utility methods from across the project into a newly created TimeUtils class.
  • Loading branch information
ypadron-in authored and burgerkingeater committed Mar 29, 2019
1 parent 3cda04e commit 4e212eb
Show file tree
Hide file tree
Showing 39 changed files with 392 additions and 525 deletions.
201 changes: 201 additions & 0 deletions az-core/src/main/java/azkaban/utils/TimeUtils.java
@@ -0,0 +1,201 @@
/*
* Copyright 2019 LinkedIn Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package azkaban.utils;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import org.joda.time.Days;
import org.joda.time.DurationFieldType;
import org.joda.time.Hours;
import org.joda.time.Minutes;
import org.joda.time.Months;
import org.joda.time.ReadablePeriod;
import org.joda.time.Seconds;
import org.joda.time.Weeks;
import org.joda.time.Years;

public class TimeUtils {

public static final String DATE_TIME_ZONE_PATTERN = "yyyy/MM/dd HH:mm:ss z";
public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

/**
* Formats the given millisecond instant into a string using the pattern "yyyy/MM/dd HH:mm:ss z"
*/
public static String formatDateTimeZone(final long timestampMs) {
return format(timestampMs, DATE_TIME_ZONE_PATTERN);
}

/**
* Formats the given millisecond instant into a string using the pattern "yyyy-MM-dd HH:mm:ss"
*/
public static String formatDateTime(final long timestampMs) {
return format(timestampMs, DATE_TIME_PATTERN);
}

private static String format(final long timestampMs, final String pattern) {
if (timestampMs < 0) {
return "-";
}
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(timestampMs),
ZoneId.systemDefault());
return formatter.format(zonedDateTime);
}

public static String formatDuration(final long startTime, final long endTime) {
if (startTime == -1) {
return "-";
}

final long durationMS;
if (endTime == -1) {
durationMS = System.currentTimeMillis() - startTime;
} else {
durationMS = endTime - startTime;
}

long seconds = durationMS / 1000;
if (seconds < 60) {
return seconds + " sec";
}

long minutes = seconds / 60;
seconds %= 60;
if (minutes < 60) {
return minutes + "m " + seconds + "s";
}

long hours = minutes / 60;
minutes %= 60;
if (hours < 24) {
return hours + "h " + minutes + "m " + seconds + "s";
}

final long days = hours / 24;
hours %= 24;
return days + "d " + hours + "h " + minutes + "m";
}

public static String formatPeriod(final ReadablePeriod period) {
String periodStr = "null";

if (period == null) {
return periodStr;
}

if (period.get(DurationFieldType.years()) > 0) {
final int years = period.get(DurationFieldType.years());
periodStr = years + " year(s)";
} else if (period.get(DurationFieldType.months()) > 0) {
final int months = period.get(DurationFieldType.months());
periodStr = months + " month(s)";
} else if (period.get(DurationFieldType.weeks()) > 0) {
final int weeks = period.get(DurationFieldType.weeks());
periodStr = weeks + " week(s)";
} else if (period.get(DurationFieldType.days()) > 0) {
final int days = period.get(DurationFieldType.days());
periodStr = days + " day(s)";
} else if (period.get(DurationFieldType.hours()) > 0) {
final int hours = period.get(DurationFieldType.hours());
periodStr = hours + " hour(s)";
} else if (period.get(DurationFieldType.minutes()) > 0) {
final int minutes = period.get(DurationFieldType.minutes());
periodStr = minutes + " minute(s)";
} else if (period.get(DurationFieldType.seconds()) > 0) {
final int seconds = period.get(DurationFieldType.seconds());
periodStr = seconds + " second(s)";
}

return periodStr;
}

public static ReadablePeriod parsePeriodString(final String periodStr) {
final ReadablePeriod period;
final char periodUnit = periodStr.charAt(periodStr.length() - 1);
if (periodStr.equals("null") || periodUnit == 'n') {
return null;
}

final int periodInt =
Integer.parseInt(periodStr.substring(0, periodStr.length() - 1));
switch (periodUnit) {
case 'y':
period = Years.years(periodInt);
break;
case 'M':
period = Months.months(periodInt);
break;
case 'w':
period = Weeks.weeks(periodInt);
break;
case 'd':
period = Days.days(periodInt);
break;
case 'h':
period = Hours.hours(periodInt);
break;
case 'm':
period = Minutes.minutes(periodInt);
break;
case 's':
period = Seconds.seconds(periodInt);
break;
default:
throw new IllegalArgumentException("Invalid schedule period unit '"
+ periodUnit);
}

return period;
}

public static String createPeriodString(final ReadablePeriod period) {
String periodStr = "null";

if (period == null) {
return "null";
}

if (period.get(DurationFieldType.years()) > 0) {
final int years = period.get(DurationFieldType.years());
periodStr = years + "y";
} else if (period.get(DurationFieldType.months()) > 0) {
final int months = period.get(DurationFieldType.months());
periodStr = months + "M";
} else if (period.get(DurationFieldType.weeks()) > 0) {
final int weeks = period.get(DurationFieldType.weeks());
periodStr = weeks + "w";
} else if (period.get(DurationFieldType.days()) > 0) {
final int days = period.get(DurationFieldType.days());
periodStr = days + "d";
} else if (period.get(DurationFieldType.hours()) > 0) {
final int hours = period.get(DurationFieldType.hours());
periodStr = hours + "h";
} else if (period.get(DurationFieldType.minutes()) > 0) {
final int minutes = period.get(DurationFieldType.minutes());
periodStr = minutes + "m";
} else if (period.get(DurationFieldType.seconds()) > 0) {
final int seconds = period.get(DurationFieldType.seconds());
periodStr = seconds + "s";
}

return periodStr;
}

}
116 changes: 0 additions & 116 deletions az-core/src/main/java/azkaban/utils/Utils.java
Expand Up @@ -38,17 +38,7 @@
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Days;
import org.joda.time.DurationFieldType;
import org.joda.time.Hours;
import org.joda.time.Minutes;
import org.joda.time.Months;
import org.joda.time.ReadablePeriod;
import org.joda.time.Seconds;
import org.joda.time.Weeks;
import org.joda.time.Years;
import org.quartz.CronExpression;

/**
Expand Down Expand Up @@ -303,40 +293,6 @@ public static Object callConstructor(final Class<?> c, final Class<?>[] argTypes
}
}

public static String formatDuration(final long startTime, final long endTime) {
if (startTime == -1) {
return "-";
}

final long durationMS;
if (endTime == -1) {
durationMS = DateTime.now().getMillis() - startTime;
} else {
durationMS = endTime - startTime;
}

long seconds = durationMS / 1000;
if (seconds < 60) {
return seconds + " sec";
}

long minutes = seconds / 60;
seconds %= 60;
if (minutes < 60) {
return minutes + "m " + seconds + "s";
}

long hours = minutes / 60;
minutes %= 60;
if (hours < 24) {
return hours + "h " + minutes + "m " + seconds + "s";
}

final long days = hours / 24;
hours %= 24;
return days + "d " + hours + "h " + minutes + "m";
}

public static Object invokeStaticMethod(final ClassLoader loader, final String className,
final String methodName, final Object... args) throws ClassNotFoundException,
SecurityException, NoSuchMethodException, IllegalArgumentException,
Expand All @@ -362,78 +318,6 @@ public static void copyStream(final InputStream input, final OutputStream output
}
}

public static ReadablePeriod parsePeriodString(final String periodStr) {
final ReadablePeriod period;
final char periodUnit = periodStr.charAt(periodStr.length() - 1);
if (periodStr.equals("null") || periodUnit == 'n') {
return null;
}

final int periodInt =
Integer.parseInt(periodStr.substring(0, periodStr.length() - 1));
switch (periodUnit) {
case 'y':
period = Years.years(periodInt);
break;
case 'M':
period = Months.months(periodInt);
break;
case 'w':
period = Weeks.weeks(periodInt);
break;
case 'd':
period = Days.days(periodInt);
break;
case 'h':
period = Hours.hours(periodInt);
break;
case 'm':
period = Minutes.minutes(periodInt);
break;
case 's':
period = Seconds.seconds(periodInt);
break;
default:
throw new IllegalArgumentException("Invalid schedule period unit '"
+ periodUnit);
}

return period;
}

public static String createPeriodString(final ReadablePeriod period) {
String periodStr = "null";

if (period == null) {
return "null";
}

if (period.get(DurationFieldType.years()) > 0) {
final int years = period.get(DurationFieldType.years());
periodStr = years + "y";
} else if (period.get(DurationFieldType.months()) > 0) {
final int months = period.get(DurationFieldType.months());
periodStr = months + "M";
} else if (period.get(DurationFieldType.weeks()) > 0) {
final int weeks = period.get(DurationFieldType.weeks());
periodStr = weeks + "w";
} else if (period.get(DurationFieldType.days()) > 0) {
final int days = period.get(DurationFieldType.days());
periodStr = days + "d";
} else if (period.get(DurationFieldType.hours()) > 0) {
final int hours = period.get(DurationFieldType.hours());
periodStr = hours + "h";
} else if (period.get(DurationFieldType.minutes()) > 0) {
final int minutes = period.get(DurationFieldType.minutes());
periodStr = minutes + "m";
} else if (period.get(DurationFieldType.seconds()) > 0) {
final int seconds = period.get(DurationFieldType.seconds());
periodStr = seconds + "s";
}

return periodStr;
}

/**
* @param strMemSize : memory string in the format such as 1G, 500M, 3000K, 5000
* @return : long value of memory amount in kb
Expand Down
Expand Up @@ -74,7 +74,8 @@
#set ($size = $paths.size() - 1)
<a class="firstCrumb" href="${context}/hdfs/"> / </a>#if($size >= 0)#foreach($i in [0 ..$size])<a href="$context/hdfs${paths.get($i)}">${segments.get($i)}</a><span> / </span>#end #end
<div class="pull-right">
<strong>$subdirs.size()</strong> items <strong>$utils.displayBytes($dirsize)</strong> total
<strong>$subdirs.size()</strong> items <strong>$WebUtils.displayBytes($dirsize)
</strong> total
</div>
</div>
<table id="hdfs-dir" class="table table-condensed table-striped table-hover table-bordered">
Expand Down Expand Up @@ -109,14 +110,14 @@
#if ($status.isDir())
&ndash;
#else
$utils.displayBytes(${status.len})
$WebUtils.displayBytes(${status.len})
#end
</td>
<td>
#if ($status.isDir())
&ndash;
#else
$utils.displayBytes(${status.getBlockSize()})
$WebUtils.displayBytes(${status.getBlockSize()})
#end
</td>
<td>
Expand All @@ -126,7 +127,7 @@
${status.getReplication()}
#end
</td>
<td>$utils.formatDateTime(${status.modificationTime})</td>
<td>$TimeUtils.formatDateTime(${status.modificationTime})</td>
</tr>
#end
#else
Expand Down
Expand Up @@ -96,15 +96,16 @@
</tr>
<tr>
<td class="property-key">Size</td>
<td class="property-value-half">$utils.displayBytes(${status.len})</td>
<td class="property-value-half">$WebUtils.displayBytes(${status.len})</td>
<td class="property-key">Block Size</td>
<td class="property-value-half">$utils.displayBytes(${status.getBlockSize()})</td>
<td class="property-value-half">$WebUtils.displayBytes(${status.getBlockSize()})
</td>
</tr>
<tr>
<td class="property-key">Reps</td>
<td class="property-value-half">${status.getReplication()}</td>
<td class="property-key">Modified Date</td>
<td class="property-value-half">$utils.formatDateTime(${status.modificationTime})</td>
<td class="property-value-half">$TimeUtils.formatDateTime(${status.modificationTime})</td>
</tr>
</tbody>
</table>
Expand Down

0 comments on commit 4e212eb

Please sign in to comment.