Pith - wedge
package com.vgmlr.wedge

import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.roundToLong

object WedgeDate {
    fun startOfDay(timestamp: Long): Long = Calendar.getInstance().apply {
        timeInMillis = timestamp
        set(Calendar.HOUR_OF_DAY, 0); set(Calendar.MINUTE, 0)
        set(Calendar.SECOND, 0); set(Calendar.MILLISECOND, 0)
    }.timeInMillis

    private fun daysBetween(fromMs: Long, toMs: Long): Long =
        ((startOfDay(toMs) - startOfDay(fromMs)) / 86_400_000.0).roundToLong()
    
    fun getOtcParts(timestamp: Long): Pair<Long, Int> {
        val cal = Calendar.getInstance().apply { timeInMillis = timestamp }
        val gYear = cal.get(Calendar.YEAR)
        val isBeforeMarch20 = (cal.get(Calendar.MONTH) < Calendar.MARCH) ||
                (cal.get(Calendar.MONTH) == Calendar.MARCH && cal.get(Calendar.DAY_OF_MONTH) < 20)
        val cycleStartYear = if (isBeforeMarch20) gYear - 1 else gYear
        val cycleStart = Calendar.getInstance().apply {
            set(Calendar.YEAR, cycleStartYear); set(Calendar.MONTH, Calendar.MARCH)
            set(Calendar.DAY_OF_MONTH, 20); set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0); set(Calendar.SECOND, 0); set(Calendar.MILLISECOND, 0)
        }
        val altDayOfYear = daysBetween(cycleStart.timeInMillis, timestamp) + 1
        return Pair(altDayOfYear, cycleStartYear % 100)
    }
    fun getOtcDate(timestamp: Long = System.currentTimeMillis()): String {
        val parts = getOtcParts(timestamp)
        val time = SimpleDateFormat("HHmm", Locale.getDefault()).format(Date(timestamp))
        return "0${parts.second}${parts.first}${time}"
    }

    fun getOtcMetadata(timestamp: Long): String {
        val parts = getOtcParts(timestamp)
        val hms = SimpleDateFormat("HH:mm", Locale.US).format(Date(timestamp))
        val dmy = SimpleDateFormat("dd MMM", Locale.US).format(Date(timestamp))
        return "$hms ${parts.first} 0${parts.second} ($dmy)"
    }

    fun getDateMath(day: Int, monthAbbr: String, yy: Int? = null): String? {
        val months = listOf("jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec")
        val monthIdx = months.indexOf(monthAbbr.lowercase())
        if (monthIdx == -1) return null
        val now = Calendar.getInstance().apply {
            set(Calendar.HOUR_OF_DAY, 0); set(Calendar.MINUTE, 0); set(Calendar.SECOND, 0); set(Calendar.MILLISECOND, 0)
        }
        val target = Calendar.getInstance().apply {
            set(Calendar.YEAR, if (yy != null) 2000 + yy else now.get(Calendar.YEAR))
            set(Calendar.MONTH, monthIdx)
            set(Calendar.DAY_OF_MONTH, day)
            set(Calendar.HOUR_OF_DAY, 0); set(Calendar.MINUTE, 0); set(Calendar.SECOND, 0); set(Calendar.MILLISECOND, 0)
        }
        if (yy == null && target.before(now)) target.add(Calendar.YEAR, 1)
        val diffUntil = daysBetween(now.timeInMillis, target.timeInMillis).coerceAtLeast(0)
        val otcDay = getOtcParts(target.timeInMillis).first
        return "($otcDay)=$diffUntil"
    }
}