diff --git a/src/commonMain/kotlin/de/kif/common/DateFormat.kt b/src/commonMain/kotlin/de/kif/common/DateFormat.kt index 9a0146a..63de1f6 100644 --- a/src/commonMain/kotlin/de/kif/common/DateFormat.kt +++ b/src/commonMain/kotlin/de/kif/common/DateFormat.kt @@ -1,19 +1,27 @@ package de.kif.common -import com.soywiz.klock.DateFormat -import com.soywiz.klock.KlockLocale -import com.soywiz.klock.format +import com.soywiz.klock.* import com.soywiz.klock.locale.german -fun formatDateTime(unix: Long) = +fun formatDateTime(unix: Long, timezone: Long) = DateFormat("EEEE, d. MMMM y HH:mm") .withLocale(KlockLocale.german) - .format(unix) + .format(DateTimeTz.utc(DateTime(unix), TimezoneOffset(timezone.toDouble()))) -fun formatDate(unix: Long) = +fun formatDate(unix: Long, timezone: Long) = DateFormat("EEEE, d. MMMM y") .withLocale(KlockLocale.german) - .format(unix) + .format(DateTimeTz.utc(DateTime(unix), TimezoneOffset(timezone.toDouble()))) + +fun formatDateWithoutYear(unix: Long, timezone: Long) = + DateFormat("EEEE, d. MMMM") + .withLocale(KlockLocale.german) + .format(DateTimeTz.utc(DateTime(unix), TimezoneOffset(timezone.toDouble()))) + +fun formatTime(unix: Long, timezone: Long) = + DateFormat("HH:mm") + .withLocale(KlockLocale.german) + .format(DateTimeTz.utc(DateTime(unix), TimezoneOffset(timezone.toDouble()))) fun formatTimeDiff(time: Long, now: Long): String { var dt = (time - now) / 1000 @@ -42,12 +50,15 @@ fun formatTimeDiff(time: Long, now: Long): String { .withLocale(KlockLocale.german) .format(time) - if ((ht.substringBefore(":").toIntOrNull() ?: 0) < nowHour ) { + if ((ht.substringBefore(":").toIntOrNull() ?: 0) < nowHour) { "morgen" } else "um $ht" } hours > 0L -> { - "in " +hours.toString().padStart(2, '0') + ":" + (minutes + if (seconds > 0) 1 else 0).toString().padStart(2, '0') + "in " + hours.toString().padStart(2, '0') + ":" + (minutes + if (seconds > 0) 1 else 0).toString().padStart( + 2, + '0' + ) } minutes > 0L -> { "in 00:" + (minutes + if (seconds > 0) 1 else 0).toString().padStart(2, '0') diff --git a/src/jsMain/kotlin/de/kif/frontend/main.kt b/src/jsMain/kotlin/de/kif/frontend/main.kt index 782ce78..8dc9572 100644 --- a/src/jsMain/kotlin/de/kif/frontend/main.kt +++ b/src/jsMain/kotlin/de/kif/frontend/main.kt @@ -10,11 +10,16 @@ import de.kif.frontend.views.overview.initPostEdit import de.kif.frontend.views.overview.initPosts import de.kif.frontend.views.table.initTableLayout import de.westermann.kwebview.components.init +import org.w3c.dom.get import kotlin.browser.document +var timezoneOffset = 0L + fun main() = init { PushServiceClient() + timezoneOffset = document.body?.dataset?.get("timezone")?.toLongOrNull() ?: 0L + if (document.getElementsByClassName("calendar").length > 0) { initCalendar() } diff --git a/src/jsMain/kotlin/de/kif/frontend/views/RoomConstraints.kt b/src/jsMain/kotlin/de/kif/frontend/views/RoomConstraints.kt index aa511e5..f0df9f4 100644 --- a/src/jsMain/kotlin/de/kif/frontend/views/RoomConstraints.kt +++ b/src/jsMain/kotlin/de/kif/frontend/views/RoomConstraints.kt @@ -1,6 +1,7 @@ package de.kif.frontend.views import de.kif.common.formatDate +import de.kif.frontend.timezoneOffset import de.westermann.kwebview.View import de.westermann.kwebview.components.InputType import de.westermann.kwebview.components.InputView @@ -22,7 +23,7 @@ fun initRoomConstraints() { fun updateDateView(inputGroup: HTMLElement, day: Int) { val date = referenceDate + (day * 1000 * 60 * 60 * 24) - val dateName = formatDate(date) + val dateName = formatDate(date, timezoneOffset) inputGroup.dataset["hint"] = dateName } @@ -69,8 +70,8 @@ fun initRoomConstraints() { }) for (e in child.children.iterator()) { - if (e.classList.contains("-day-")) { - val input = InputView.wrap(e as HTMLInputElement) + if (e is HTMLInputElement && e.name.contains("-day-")) { + val input = InputView.wrap(e) updateDateView(child, input.value.toIntOrNull() ?: 0) input.valueProperty.onChange { diff --git a/src/jsMain/kotlin/de/kif/frontend/views/WorkGroupConstraints.kt b/src/jsMain/kotlin/de/kif/frontend/views/WorkGroupConstraints.kt index b8fb1b4..c871795 100644 --- a/src/jsMain/kotlin/de/kif/frontend/views/WorkGroupConstraints.kt +++ b/src/jsMain/kotlin/de/kif/frontend/views/WorkGroupConstraints.kt @@ -4,6 +4,7 @@ import de.kif.common.formatDate import de.kif.frontend.launch import de.kif.frontend.repository.RoomRepository import de.kif.frontend.repository.WorkGroupRepository +import de.kif.frontend.timezoneOffset import de.westermann.kobserve.event.EventListener import de.westermann.kwebview.View import de.westermann.kwebview.async @@ -41,7 +42,7 @@ fun initWorkGroupConstraints() { fun updateDateView(inputGroup: HTMLElement, day: Int) { val date = referenceDate + (day * 1000 * 60 * 60 * 24) - val dateName = formatDate(date) + val dateName = formatDate(date, timezoneOffset) inputGroup.dataset["hint"] = dateName } @@ -279,8 +280,8 @@ fun initWorkGroupConstraints() { }) for (e in child.children.iterator()) { - if (e.classList.contains("-day-")) { - val input = InputView.wrap(e as HTMLInputElement) + if (e is HTMLInputElement && e.name.contains("-day-")) { + val input = InputView.wrap(e) updateDateView(child, input.value.toIntOrNull() ?: 0) input.valueProperty.onChange { diff --git a/src/jsMain/kotlin/de/kif/frontend/views/board/Board.kt b/src/jsMain/kotlin/de/kif/frontend/views/board/Board.kt index bc34286..c19800b 100644 --- a/src/jsMain/kotlin/de/kif/frontend/views/board/Board.kt +++ b/src/jsMain/kotlin/de/kif/frontend/views/board/Board.kt @@ -1,11 +1,10 @@ package de.kif.frontend.views.board -import com.soywiz.klock.DateFormat -import com.soywiz.klock.DateTimeTz -import com.soywiz.klock.KlockLocale -import com.soywiz.klock.locale.german +import de.kif.common.formatDate +import de.kif.common.formatTime import de.kif.frontend.launch import de.kif.frontend.repository.ScheduleRepository +import de.kif.frontend.timezoneOffset import de.kif.frontend.views.overview.getByClassOrCreate import de.westermann.kwebview.interval import de.westermann.kwebview.iterator @@ -26,7 +25,6 @@ fun initBoard() { val referenceInitTime = dateContainer.dataset["now"]?.toLongOrNull() ?: initTime val diff = initTime - referenceInitTime - val boardRunning = document.getElementsByClassName("board-running")[0] as HTMLElement val scheduleList = mutableListOf() val runningReferenceTime = boardRunning.dataset["reference"]?.toLongOrNull() ?: 0L @@ -58,16 +56,8 @@ fun initBoard() { interval(1000) { val now = Date.now().toLong() + diff - val dt = DateTimeTz.fromUnixLocal(now) - - timeView.textContent = DateFormat("HH:mm") - .withLocale(KlockLocale.german) - .format(dt) - - dateView.textContent = DateFormat("EEEE, d. MMMM y") - .withLocale(KlockLocale.german) - .format(dt) - + timeView.textContent = formatTime(now, timezoneOffset) + dateView.textContent = formatDate(now, timezoneOffset) scheduleList.forEach { it.updateTime(now) } } diff --git a/src/jsMain/kotlin/de/kif/frontend/views/overview/PostView.kt b/src/jsMain/kotlin/de/kif/frontend/views/overview/PostView.kt index df2f59c..4396227 100644 --- a/src/jsMain/kotlin/de/kif/frontend/views/overview/PostView.kt +++ b/src/jsMain/kotlin/de/kif/frontend/views/overview/PostView.kt @@ -3,6 +3,7 @@ package de.kif.frontend.views.overview import de.kif.common.formatDateTime import de.kif.frontend.launch import de.kif.frontend.repository.PostRepository +import de.kif.frontend.timezoneOffset import de.westermann.kobserve.event.emit import de.westermann.kwebview.View import de.westermann.kwebview.components.Link @@ -45,7 +46,7 @@ class PostView( } contentView.innerHTML = PostRepository.htmlByUrl(p.url) - footerView.innerText = formatDateTime(p.createdAt) + footerView.innerText = formatDateTime(p.createdAt, timezoneOffset) emit(PostChangeEvent(postId)) } diff --git a/src/jvmMain/kotlin/de/kif/backend/Configuration.kt b/src/jvmMain/kotlin/de/kif/backend/Configuration.kt index 038f8b1..8bc2773 100644 --- a/src/jvmMain/kotlin/de/kif/backend/Configuration.kt +++ b/src/jvmMain/kotlin/de/kif/backend/Configuration.kt @@ -77,7 +77,13 @@ object Configuration { val referenceDate: Date by lazy { val sdf = SimpleDateFormat("yyyy-MM-dd") sdf.timeZone = TimeZone.getTimeZone(ZoneId.of("UTC")) - sdf.parse(reference) + val calendar = Calendar.getInstance() + calendar.time = sdf.parse(reference) + calendar.set(Calendar.HOUR_OF_DAY, 0) + calendar.set(Calendar.MINUTE, 0) + calendar.set(Calendar.SECOND, 0) + calendar.set(Calendar.MILLISECOND, 0) + calendar.time } val offset by c(ScheduleSpec.offset) diff --git a/src/jvmMain/kotlin/de/kif/backend/route/Board.kt b/src/jvmMain/kotlin/de/kif/backend/route/Board.kt index 7ed335e..5df9215 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/Board.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/Board.kt @@ -25,7 +25,7 @@ data class BoardSchedule( suspend fun getUpcoming(limit: Int = 8): List { val now = - ((Date().time + Configuration.Schedule.offset) / (1000 * 60)).toInt() - + ((Date().time) / (1000 * 60)).toInt() - (Configuration.Schedule.referenceDate.time / (1000 * 60)) return ScheduleRepository.all() .map { @@ -49,7 +49,6 @@ fun Route.board() { val now = Date() val referenceTime = Configuration.Schedule.referenceDate.time - val timeOffset = Configuration.Schedule.offset val refDate = Configuration.Schedule.referenceDate @@ -86,7 +85,7 @@ fun Route.board() { min = (min / 60 - 1) * 60 max = (max / 60 + 2) * 60 - val nowLocale = now.time + timeOffset + val nowLocale = now.time respondMain(true, true) { theme -> content { val announcement = AnnouncementRepository.getAnnouncement() @@ -162,7 +161,7 @@ fun Route.board() { div("board-logo") { img("KIF 47.0", "$prefix/static/images/logo.svg") div("board-header-date") { - attributes["data-now"] = (now.time - timeOffset).toString() + attributes["data-now"] = (now.time).toString() } } } diff --git a/src/jvmMain/kotlin/de/kif/backend/route/Calendar.kt b/src/jvmMain/kotlin/de/kif/backend/route/Calendar.kt index 6c53dab..65ee77c 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/Calendar.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/Calendar.kt @@ -1,7 +1,7 @@ package de.kif.backend.route import com.soywiz.klock.* -import com.soywiz.klock.locale.german +import com.soywiz.klock.jvm.toDateTime import de.kif.backend.Configuration import de.kif.backend.isAuthenticated import de.kif.backend.prefix @@ -10,6 +10,7 @@ import de.kif.backend.repository.ScheduleRepository import de.kif.backend.repository.TrackRepository import de.kif.backend.view.respondMain import de.kif.common.CALENDAR_GRID_WIDTH +import de.kif.common.formatDateWithoutYear import de.kif.common.model.Permission import de.kif.common.model.Room import de.kif.common.model.Schedule @@ -148,7 +149,7 @@ fun DIV.renderCalendar( val cellSchedules = (start..end).flatMap { schedules[room]?.get(it) ?: emptyList() } - for(schedule in cellSchedules) { + for (schedule in cellSchedules) { calendarEntry(schedule, diff, currentTime) } } @@ -266,9 +267,7 @@ fun Route.calendar() { val refDate = DateTime(Configuration.Schedule.referenceDate.time) val date = refDate + day.days - val dateString = DateFormat("EEEE, d. MMMM") - .withLocale(KlockLocale.german) - .format(date) + val dateString = formatDateWithoutYear(date.unixMillisLong, Configuration.Schedule.offset) respondMain { content { diff --git a/src/jvmMain/kotlin/de/kif/backend/route/News.kt b/src/jvmMain/kotlin/de/kif/backend/route/News.kt index 4d3662b..0f2d2ef 100644 --- a/src/jvmMain/kotlin/de/kif/backend/route/News.kt +++ b/src/jvmMain/kotlin/de/kif/backend/route/News.kt @@ -60,7 +60,7 @@ fun DIV.createPost(post: Post, editable: Boolean = false, additionalClasses: Str } } div("post-footer") { - +formatDateTime(post.createdAt) + +formatDateTime(post.createdAt, Configuration.Schedule.offset) } } } diff --git a/src/jvmMain/kotlin/de/kif/backend/view/MainTemplate.kt b/src/jvmMain/kotlin/de/kif/backend/view/MainTemplate.kt index 2e5785d..2ef0e49 100644 --- a/src/jvmMain/kotlin/de/kif/backend/view/MainTemplate.kt +++ b/src/jvmMain/kotlin/de/kif/backend/view/MainTemplate.kt @@ -1,5 +1,6 @@ package de.kif.backend.view +import de.kif.backend.Configuration import de.kif.backend.PortalSession import de.kif.backend.Resources import de.kif.backend.prefix @@ -74,9 +75,11 @@ class MainTemplate( } } } + body { attributes["data-timestamp"] = currentTimeMillis().toString() attributes["data-signature"] = PushService.signature + attributes["data-timezone"] = Configuration.Schedule.offset.toString() if (!noMenu) { insert(MenuTemplate(url, user)) {}