Skip to content

Commit

Permalink
Fix timezone issues in Live TV guide
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsvanvelzen committed Jul 16, 2024
1 parent f5e1b18 commit 5891264
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -92,8 +91,8 @@ public class LiveTvGuideFragment extends Fragment implements LiveTvGuide, View.O
private boolean focusAtEnd;
private GuideFilters mFilters = new GuideFilters();

private Calendar mCurrentGuideStart;
private Calendar mCurrentGuideEnd;
private LocalDateTime mCurrentGuideStart;
private LocalDateTime mCurrentGuideEnd;
private long mCurrentLocalGuideStart = Instant.now().toEpochMilli();
private long mCurrentLocalGuideEnd;
private int mCurrentDisplayChannelStartNdx = 0;
Expand Down Expand Up @@ -702,28 +701,29 @@ private LinearLayout getProgramRow(List<BaseItemDto> programs, UUID channelId) {
}

private void fillTimeLine(long start, int hours) {
mCurrentGuideStart = Calendar.getInstance();
mCurrentGuideStart.setTime(new Date(start));
mCurrentGuideStart.set(Calendar.MINUTE, mCurrentGuideStart.get(Calendar.MINUTE) >= 30 ? 30 : 0);
mCurrentGuideStart.set(Calendar.SECOND, 0);
mCurrentGuideStart.set(Calendar.MILLISECOND, 0);
mCurrentLocalGuideStart = mCurrentGuideStart.getTimeInMillis();

mDisplayDate.setText(TimeUtils.getFriendlyDate(requireContext(), mCurrentGuideStart.getTime()));
Calendar current = (Calendar) mCurrentGuideStart.clone();
mCurrentGuideEnd = (Calendar) mCurrentGuideStart.clone();
mCurrentGuideStart = LocalDateTime.ofInstant(Instant.ofEpochMilli(start), ZoneOffset.UTC);
mCurrentGuideStart = mCurrentGuideStart
.withMinute(mCurrentGuideStart.getMinute() >= 30 ? 30 : 0)
.withSecond(0)
.withNano(0);
mCurrentLocalGuideStart = mCurrentGuideStart.toInstant(ZoneOffset.UTC).toEpochMilli();

mDisplayDate.setText(TimeUtils.getFriendlyDate(requireContext(), TimeUtils.getDate(mCurrentGuideStart)));
mCurrentGuideEnd = mCurrentGuideStart
.plusHours(hours);
int oneHour = 60 * guideRowWidthPerMinPx;
int halfHour = 30 * guideRowWidthPerMinPx;
int interval = current.get(Calendar.MINUTE) >= 30 ? 30 : 60;
mCurrentGuideEnd.add(Calendar.HOUR, hours);
mCurrentLocalGuideEnd = mCurrentGuideEnd.getTimeInMillis();
int interval = mCurrentGuideStart.getMinute() >= 30 ? 30 : 60;
mCurrentLocalGuideEnd = mCurrentGuideEnd.toInstant(ZoneOffset.UTC).toEpochMilli();
mTimeline.removeAllViews();
while (current.before(mCurrentGuideEnd)) {

LocalDateTime current = mCurrentGuideStart;
while (current.isBefore(mCurrentGuideEnd)) {
TextView time = new TextView(requireContext());
time.setText(android.text.format.DateFormat.getTimeFormat(requireContext()).format(current.getTime()));
time.setText(android.text.format.DateFormat.getTimeFormat(requireContext()).format(TimeUtils.getDate(current)));
time.setWidth(interval == 30 ? halfHour : oneHour);
mTimeline.addView(time);
current.add(Calendar.MINUTE, interval);
current = current.plusMinutes(interval);
//after first one, we always go on hours
interval = 60;
}
Expand Down
20 changes: 6 additions & 14 deletions app/src/main/java/org/jellyfin/androidtv/ui/livetv/TvManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import java.util.function.Function;

Expand Down Expand Up @@ -120,25 +118,19 @@ private static int fillChannelIds() {
return ndx;
}

public static void getProgramsAsync(Fragment fragment, int startNdx, int endNdx, final Calendar start, Calendar endTime, final EmptyLifecycleAwareResponse outerResponse) {
start.set(Calendar.MINUTE, start.get(Calendar.MINUTE) >= 30 ? 30 : 0);
start.set(Calendar.SECOND, 1);
LocalDateTime startDateTime = LocalDateTime.ofInstant(start.toInstant(), start.getTimeZone().toZoneId());
public static void getProgramsAsync(Fragment fragment, int startNdx, int endNdx, final LocalDateTime startTime, LocalDateTime endTime, final EmptyLifecycleAwareResponse outerResponse) {
LocalDateTime startTimeRounded = startTime.withMinute(startTime.getMinute() >= 30 ? 30 : 0).withSecond(0).withNano(0);
LocalDateTime endTimeRounded = endTime.minusSeconds(1);

if (forceReload || needLoadTime == null || startDateTime.isAfter(needLoadTime) || !mProgramsDict.containsKey(channelIds[startNdx]) || !mProgramsDict.containsKey(channelIds[endNdx])) {
if (forceReload || needLoadTime == null || startTimeRounded.isAfter(needLoadTime) || !mProgramsDict.containsKey(channelIds[startNdx]) || !mProgramsDict.containsKey(channelIds[endNdx])) {
forceReload = false;

endNdx = endNdx > channelIds.length ? channelIds.length : endNdx+1; //array copy range final ndx is exclusive
Calendar end = (Calendar) endTime.clone();
end.setTimeZone(TimeZone.getTimeZone("Z"));
end.add(Calendar.SECOND, -1);

LocalDateTime endDateTime = LocalDateTime.ofInstant(end.toInstant(), end.getTimeZone().toZoneId());

TvManagerHelperKt.getPrograms(fragment, Arrays.copyOfRange(channelIds, startNdx, endNdx), startDateTime, endDateTime, programs -> {
TvManagerHelperKt.getPrograms(fragment, Arrays.copyOfRange(channelIds, startNdx, endNdx), startTimeRounded, endTimeRounded, programs -> {
if (programs != null) {
Timber.d("*** About to build dictionary");
buildProgramsDict(programs, startDateTime);
buildProgramsDict(programs, startTimeRounded);
Timber.d("*** Programs retrieval finished");

if (outerResponse.getActive()) outerResponse.onResponse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;

Expand All @@ -109,8 +108,8 @@ public class CustomPlaybackOverlayFragment extends Fragment implements LiveTvGui
BaseItemDto mSelectedProgram;
RelativeLayout mSelectedProgramView;
private boolean mGuideVisible = false;
private Calendar mCurrentGuideStart;
private Calendar mCurrentGuideEnd;
private LocalDateTime mCurrentGuideStart;
private LocalDateTime mCurrentGuideEnd;
private long mCurrentLocalGuideStart;
private long mCurrentLocalGuideEnd;
private int mCurrentDisplayChannelStartNdx = 0;
Expand Down Expand Up @@ -756,12 +755,11 @@ public void showGuide() {
playbackControllerContainer.getValue().getPlaybackController().mVideoManager.contractVideo(Utils.convertDpToPixel(requireContext(), 300));
tvGuideBinding.getRoot().setVisibility(View.VISIBLE);
mGuideVisible = true;
Calendar now = Calendar.getInstance();
LocalDateTime now = LocalDateTime.now();
boolean needLoad = mCurrentGuideStart == null;
if (!needLoad) {
Calendar needLoadTime = (Calendar) mCurrentGuideStart.clone();
needLoadTime.add(Calendar.MINUTE, 30);
needLoad = now.after(needLoadTime);
LocalDateTime needLoadTime = mCurrentGuideStart.plusMinutes(30);
needLoad = now.isAfter(needLoadTime);
if (mSelectedProgramView != null)
mSelectedProgramView.requestFocus();
}
Expand Down Expand Up @@ -1007,27 +1005,29 @@ private LinearLayout getProgramRow(List<BaseItemDto> programs, UUID channelId) {
}

private void fillTimeLine(int hours) {
mCurrentGuideStart = Calendar.getInstance();
mCurrentGuideStart.set(Calendar.MINUTE, mCurrentGuideStart.get(Calendar.MINUTE) >= 30 ? 30 : 0);
mCurrentGuideStart.set(Calendar.SECOND, 0);
mCurrentGuideStart.set(Calendar.MILLISECOND, 0);
mCurrentLocalGuideStart = mCurrentGuideStart.getTimeInMillis();

tvGuideBinding.displayDate.setText(TimeUtils.getFriendlyDate(requireContext(), mCurrentGuideStart.getTime()));
Calendar current = (Calendar) mCurrentGuideStart.clone();
mCurrentGuideEnd = (Calendar) mCurrentGuideStart.clone();
mCurrentGuideStart = LocalDateTime.now();
mCurrentGuideStart = mCurrentGuideStart
.withMinute(mCurrentGuideStart.getMinute() >= 30 ? 30 : 0)
.withSecond(0)
.withNano(0);
mCurrentLocalGuideStart = mCurrentGuideStart.toInstant(ZoneOffset.UTC).toEpochMilli();

tvGuideBinding.displayDate.setText(TimeUtils.getFriendlyDate(requireContext(), TimeUtils.getDate(mCurrentGuideStart)));
mCurrentGuideEnd = mCurrentGuideStart
.plusHours(hours);
int oneHour = 60 * Utils.convertDpToPixel(requireContext(), 7);
int halfHour = 30 * Utils.convertDpToPixel(requireContext(), 7);
int interval = current.get(Calendar.MINUTE) >= 30 ? 30 : 60;
mCurrentGuideEnd.add(Calendar.HOUR, hours);
mCurrentLocalGuideEnd = mCurrentGuideEnd.getTimeInMillis();
int interval = mCurrentGuideStart.getMinute() >= 30 ? 30 : 60;
mCurrentLocalGuideEnd = mCurrentGuideEnd.toInstant(ZoneOffset.UTC).toEpochMilli();
tvGuideBinding.timeline.removeAllViews();
while (current.before(mCurrentGuideEnd)) {

LocalDateTime current = mCurrentGuideStart;
while (current.isBefore(mCurrentGuideEnd)) {
TextView time = new TextView(requireContext());
time.setText(android.text.format.DateFormat.getTimeFormat(requireContext()).format(current.getTime()));
time.setText(android.text.format.DateFormat.getTimeFormat(requireContext()).format(TimeUtils.getDate(current)));
time.setWidth(interval == 30 ? halfHour : oneHour);
tvGuideBinding.timeline.addView(time);
current.add(Calendar.MINUTE, interval);
current = current.plusMinutes(interval);
//after first one, we always go on hours
interval = 60;
}
Expand Down
32 changes: 0 additions & 32 deletions app/src/main/java/org/jellyfin/androidtv/util/TimeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

public class TimeUtils {
Expand Down Expand Up @@ -61,36 +59,6 @@ public static String formatSeconds(Context context, int seconds) {
}
}

public static Date convertToLocalDate(Date utcDate) {
TimeZone timeZone = Calendar.getInstance().getTimeZone();
Date convertedDate = new Date(utcDate.getTime() + timeZone.getRawOffset());

if (timeZone.inDaylightTime(convertedDate)) {
Date dstDate = new Date(convertedDate.getTime() + timeZone.getDSTSavings());

if (timeZone.inDaylightTime(dstDate)) {
return dstDate;
}
}

return convertedDate;
}

public static Date convertToUtcDate(Date localDate) {
TimeZone timeZone = Calendar.getInstance().getTimeZone();
Date convertedDate = new Date(localDate.getTime() - timeZone.getRawOffset());

if (timeZone.inDaylightTime(localDate)) {
Date dstDate = new Date(convertedDate.getTime() - timeZone.getDSTSavings());

if (timeZone.inDaylightTime(dstDate)) {
return dstDate;
}
}

return convertedDate;
}

public static String getFriendlyDate(Context context, Date date) {
return getFriendlyDate(context, date, false);
}
Expand Down

0 comments on commit 5891264

Please sign in to comment.