in atlas-chart/src/main/scala/com/netflix/atlas/chart/graphics/Ticks.scala [584:626]
def time(s: Long, e: Long, zone: ZoneId, n: Int): List[TimeTick] = {
// To keep even placement of major grid lines the shift amount for the timezone is computed
// based on the start. If there is a change such as DST during the interval, then labels
// after the change may be on less significant boundaries.
val shift = zone.getRules.getOffset(Instant.ofEpochMilli(s)).getTotalSeconds * 1000L
val dur = e - s
val candidates = timeTickSizes.filter(t => dur / t._1 <= n)
if (candidates.nonEmpty) {
val (major, minor) = candidates.head
val ticks = List.newBuilder[TimeTick]
val zs = s + shift
val ze = e + shift
var pos = zs / major * major
while (pos <= ze) {
if (pos >= zs) ticks += TimeTick(pos - shift, zone, pos % major == 0L)
pos += minor
}
ticks.result()
} else {
val start = LocalDateTime.ofInstant(Instant.ofEpochMilli(s), zone).toLocalDate
val end = LocalDateTime.ofInstant(Instant.ofEpochMilli(e), zone).toLocalDate
val days = dur / (24 * 60 * 60 * 1000L)
val (amount, unit, fmt) = days match {
case d if d <= n => (1L, ChronoUnit.DAYS, defaultTimeFmt)
case d if d / 30 <= n => (1L, ChronoUnit.MONTHS, monthTimeFmt)
case d if d / 90 <= n => (3L, ChronoUnit.MONTHS, monthTimeFmt)
case d if d / 365 <= n => (1L, ChronoUnit.YEARS, yearTimeFmt)
case d => (d / (n * 365), ChronoUnit.YEARS, yearTimeFmt)
}
val ticks = List.newBuilder[TimeTick]
var t = start
while (t.isBefore(end) || t.isEqual(end)) {
val timestamp = t.atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli - shift
ticks += TimeTick(timestamp, zone, formatter = Some(fmt))
t = t.plus(amount, unit)
}
ticks.result()
}
}