Skip to content

Instantly share code, notes, and snippets.

@XerxesZorgon
Created April 7, 2025 15:00
Show Gist options
  • Select an option

  • Save XerxesZorgon/a8a728ce10bef894f3f1c53bdc532c36 to your computer and use it in GitHub Desktop.

Select an option

Save XerxesZorgon/a8a728ce10bef894f3f1c53bdc532c36 to your computer and use it in GitHub Desktop.
Buckaroo Time app for Android. Calculates solar time based on phone's GPS location and UTC time.
package com.example.buckarootime
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Looper
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.core.app.ActivityCompat
import com.example.buckarootime.ui.theme.BuckarooTimeTheme
import com.google.android.gms.location.*
import java.time.ZoneOffset
import java.time.ZonedDateTime
import kotlin.math.*
import androidx.compose.ui.unit.dp
import java.util.Locale
class MainActivity : ComponentActivity() {
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
val solarTimeState = mutableStateOf("Calculating...")
locationRequest = LocationRequest.Builder(
Priority.PRIORITY_HIGH_ACCURACY, 60000L
).apply {
setMinUpdateIntervalMillis(5000L)
}.build()
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
for (location in locationResult.locations) {
val longitude = location.longitude
val solarTime = calculateSolarTime(longitude)
solarTimeState.value = "Solar Time: $solarTime\nLongitude: $longitude"
}
}
}
requestPermission {
if (it && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
try {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
} catch (e: SecurityException) {
solarTimeState.value = "SecurityException: ${e.message}"
}
} else {
solarTimeState.value = "Permission Denied"
}
}
setContent {
BuckarooTimeTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { padding ->
Column(
modifier = Modifier
.padding(padding)
.padding(16.dp)
) {
Text(text = "Buckaroo Time", style = MaterialTheme.typography.headlineMedium)
Spacer(modifier = Modifier.height(16.dp))
Text(text = solarTimeState.value, style = MaterialTheme.typography.bodyLarge)
}
}
}
}
}
private fun requestPermission(onResult: (Boolean) -> Unit) {
val launcher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted -> onResult(granted) }
when {
ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED -> onResult(true)
else -> launcher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
}
private fun calculateSolarTime(longitude: Double): String {
val nowUtc = ZonedDateTime.now(ZoneOffset.UTC)
val eotMinutes = equationOfTime(nowUtc.dayOfYear)
val timeCorrectionMinutes = (4.0 * longitude) + eotMinutes
val utcMinutesPastMidnight = nowUtc.hour * 60 + nowUtc.minute + nowUtc.second / 60.0
var latMinutesPastMidnight = utcMinutesPastMidnight + timeCorrectionMinutes
latMinutesPastMidnight = (latMinutesPastMidnight % 1440 + 1440) % 1440
val latHours = (latMinutesPastMidnight / 60).toInt()
val latMinutes = (latMinutesPastMidnight % 60).toInt()
val latSeconds = ((latMinutesPastMidnight * 60) % 60).toInt()
return String.format(Locale.US, "%02d:%02d:%02d", latHours, latMinutes, latSeconds)
}
private fun equationOfTime(dayOfYear: Int): Double {
val b = 2 * Math.PI * (dayOfYear - 81) / 365
return 9.87 * sin(2 * b) - 7.53 * cos(b) - 1.5 * sin(b)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment