Permalink
Browse files

Fix scheduler related issues resulting from the UTC changes.

By definition kTimeslot and kWeekslot recording rules work on local
time.  Change the scheduler to convert UTC times back to local time on
the fly as needed.

IMPORTANT NOTE: This means MythTV now needs working time zone support
in MySQL.  Because time zone support is not typically configured in
MySQL by most distributions at this time, users will need to do that
themselves.  See the following URL for more information.

  http://dev.mysql.com/doc/refman/5.5/en/mysql-tzinfo-to-sql.html

In mythtv-setup and mythbackend, check the MySQL time zone support and
exit immediately if it is not working.

It's simpler to keep record.findday and findtime in local time at this
point.  Undo part of schema upgrade 1305 and update RecordingRule to
accomplish that.

Change the other, recent time zone related schema upgrades to use
CONVERT_TZ() instead of simply adding the utc_offset in minutes.  This
is so future upgraders will not have the "off by 1 hour" problem on
some historical times.
  • Loading branch information...
gigem committed Jun 16, 2012
1 parent b0a0e56 commit 181641abbdd76e3e65f4d8bd0d9979b566a0b9f2
@@ -115,7 +115,7 @@ package MythTV;
# schema version supported in the main code. We need to check that the schema
# version in the database is as expected by the bindings, which are expected
# to be kept in sync with the main code.
- our $SCHEMA_VERSION = "1305";
+ our $SCHEMA_VERSION = "1306";
# NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is
# the number of items in a ProgramInfo QStringList group used by
@@ -5,7 +5,7 @@
"""
OWN_VERSION = (0,26,-1,1)
-SCHEMA_VERSION = 1305
+SCHEMA_VERSION = 1306
NVSCHEMA_VERSION = 1007
MUSICSCHEMA_VERSION = 1018
PROTO_VERSION = '75'
@@ -867,4 +867,20 @@ void DBUtil::UnlockSchema(MSqlQuery &query)
query.exec();
}
+/** \fn CheckTimeZoneSupport(void)
+ * \brief Check if MySQL has working timz zone support.
+ */
+bool DBUtil::CheckTimeZoneSupport(void)
+{
+ MSqlQuery query(MSqlQuery::InitCon());
+ query.prepare("SELECT CONVERT_TZ(NOW(), 'SYSTEM', 'UTC')");
+ if (!query.exec() || !query.next())
+ {
+ LOG(VB_GENERAL, LOG_ERR, "MySQL time zone support check failed");
+ return false;
+ }
+
+ return !query.value(0).isNull();
+}
+
/* vim: set expandtab tabstop=4 shiftwidth=4: */
@@ -49,6 +49,8 @@ class MBASE_PUBLIC DBUtil
static bool TryLockSchema(MSqlQuery &, uint timeout_secs);
static void UnlockSchema(MSqlQuery &);
+ static bool CheckTimeZoneSupport(void);
+
static const int kUnknownVersionNumber;
protected:
@@ -33,5 +33,6 @@
#define GENERIC_EXIT_DEADLOCK 150 ///< Transcode deadlock detected
#define GENERIC_EXIT_IN_USE 151 ///< Recording in use, can't flag
#define GENERIC_EXIT_START 152 ///< MythSystem process starting
+#define GENERIC_EXIT_DB_NOTIMEZONE 153 ///< Missing DB time zone support
#endif // __MYTH_EXIT_CODES__
@@ -57,7 +57,7 @@
* mythtv/bindings/php/MythBackend.php
#endif
-#define MYTH_DATABASE_VERSION "1305"
+#define MYTH_DATABASE_VERSION "1306"
MBASE_PUBLIC const char *GetMythSourceVersion();
@@ -2061,36 +2061,42 @@ NULL
for (uint i = 0; i < sizeof(with_endtime)/sizeof(char*); i++)
{
updates_ba.push_back(
- QString("UPDATE %1 "
- "SET starttime = starttime + interval %2 minute, "
- " endtime = endtime + interval %3 minute "
- "ORDER BY %4")
- .arg(with_endtime[i]).arg(utc_offset).arg(utc_offset)
- .arg(order).toLocal8Bit());
+ QString("UPDATE %1 "
+ "SET starttime = "
+ " CONVERT_TZ(starttime, 'SYSTEM', 'UTC'), "
+ " endtime = "
+ " CONVERT_TZ(endtime, 'SYSTEM', 'UTC') "
+ "ORDER BY %4")
+ .arg(with_endtime[i])
+ .arg(order).toLocal8Bit());
}
for (uint i = 0; i < sizeof(without_endtime)/sizeof(char*); i++)
{
updates_ba.push_back(
- QString("UPDATE %1 "
- "SET starttime = starttime + interval %2 minute "
- "ORDER BY %3")
- .arg(without_endtime[i]).arg(utc_offset).arg(order)
- .toLocal8Bit());
+ QString("UPDATE %1 "
+ "SET starttime = "
+ " CONVERT_TZ(starttime, 'SYSTEM', 'UTC') "
+ "ORDER BY %3")
+ .arg(without_endtime[i]).arg(order)
+ .toLocal8Bit());
}
updates_ba.push_back(
- QString("UPDATE oldprogram "
- "SET airdate = airdate + interval %2 minute "
- "ORDER BY %3")
- .arg(utc_offset).arg((utc_offset > 0) ? "-airdate" : "airdate")
- .toLocal8Bit());
+ QString("UPDATE oldprogram "
+ "SET airdate = "
+ " CONVERT_TZ(airdate, 'SYSTEM', 'UTC') "
+ "ORDER BY %3")
+ .arg((utc_offset > 0) ? "-airdate" :
+ "airdate").toLocal8Bit());
updates_ba.push_back(
- QString("UPDATE recorded "
- "set progstart = progstart + interval %1 minute, "
- " progend = progend + interval %2 minute ")
- .arg(utc_offset).arg(utc_offset).toLocal8Bit());
+ QString("UPDATE recorded "
+ "set progstart = "
+ " CONVERT_TZ(progstart, 'SYSTEM', 'UTC'), "
+ " progend = "
+ " CONVERT_TZ(progend, 'SYSTEM', 'UTC') ")
+ .toLocal8Bit());
}
// Convert DATETIME back to seperate DATE and TIME in record table
@@ -2143,22 +2149,20 @@ NULL
for (uint i = 0; i < sizeof(with_endtime)/sizeof(char*); i++)
{
updates_ba.push_back(
- QString("UPDATE %1 "
- "SET starttime = starttime + interval %2 minute, "
- " endtime = endtime + interval %3 minute "
- "ORDER BY %4")
- .arg(with_endtime[i]).arg(utc_offset).arg(utc_offset)
- .arg(order).toLocal8Bit());
+ QString("UPDATE %1 "
+ "SET starttime = CONVERT_TZ(starttime, 'SYSTEM', 'UTC'), "
+ " endtime = CONVERT_TZ(endtime, 'SYSTEM', 'UTC') "
+ "ORDER BY %4")
+ .arg(with_endtime[i]).arg(order).toLocal8Bit());
}
for (uint i = 0; i < sizeof(without_endtime)/sizeof(char*); i++)
{
updates_ba.push_back(
- QString("UPDATE %1 "
- "SET starttime = starttime + interval %2 minute "
- "ORDER BY %3")
- .arg(without_endtime[i]).arg(utc_offset).arg(order)
- .toLocal8Bit());
+ QString("UPDATE %1 "
+ "SET starttime = CONVERT_TZ(starttime, 'SYSTEM', 'UTC') "
+ "ORDER BY %3")
+ .arg(without_endtime[i]).arg(order).toLocal8Bit());
}
}
@@ -2176,11 +2180,6 @@ NULL
if (dbver == "1304")
{
- QDateTime loc = QDateTime::currentDateTime();
- QDateTime utc = loc.toUTC();
- loc = QDateTime(loc.date(), loc.time(), Qt::UTC);
- int utc_offset = loc.secsTo(utc) / 60;
-
QList<QByteArray> updates_ba;
updates_ba.push_back(
@@ -2190,15 +2189,16 @@ NULL
"WHERE filterid=3");
updates_ba.push_back(QString(
-"UPDATE record SET "
-"findday = DAYOFWEEK(ADDTIME('2012-06-02 00:00:00', findtime) "
-" + INTERVAL %1 MINUTE + INTERVAL findday DAY) "
-"WHERE findday > 0").arg(utc_offset).toLocal8Bit());
+"UPDATE record SET findday = "
+" DAYOFWEEK(CONVERT_TZ(ADDTIME('2012-06-02 00:00:00', findtime), "
+" 'SYSTEM', 'UTC') + INTERVAL findday DAY) "
+"WHERE findday > 0").toLocal8Bit());
updates_ba.push_back(QString(
-"UPDATE record SET "
-"findtime = TIME(ADDTIME('2012-06-02 00:00:00', findtime) "
-" + INTERVAL %1 MINUTE)").arg(utc_offset).toLocal8Bit());
+"UPDATE record SET findtime = "
+" TIME(CONVERT_TZ(ADDTIME('2012-06-02 00:00:00', findtime), "
+" 'SYSTEM', 'UTC')) ")
+ .toLocal8Bit());
// Convert update ByteArrays to NULL terminated char**
QList<QByteArray>::const_iterator it = updates_ba.begin();
@@ -2211,6 +2211,35 @@ NULL
return false;
}
+ if (dbver == "1305")
+ {
+ // Reverse the findday/findtime changes from above since those
+ // values need to be kept in local time.
+
+ QList<QByteArray> updates_ba;
+
+ updates_ba.push_back(QString(
+"UPDATE record SET findday = "
+" DAYOFWEEK(CONVERT_TZ(ADDTIME('2012-06-02 00:00:00', findtime), "
+" 'UTC', 'SYSTEM') + INTERVAL findday DAY) "
+"WHERE findday > 0").toLocal8Bit());
+
+ updates_ba.push_back(QString(
+"UPDATE record SET findtime = "
+" TIME(CONVERT_TZ(ADDTIME('2012-06-02 00:00:00', findtime), "
+" 'UTC', 'SYSTEM')) ").toLocal8Bit());
+
+ // Convert update ByteArrays to NULL terminated char**
+ QList<QByteArray>::const_iterator it = updates_ba.begin();
+ vector<const char*> updates;
+ for (; it != updates_ba.end(); ++it)
+ updates.push_back((*it).constData());
+ updates.push_back(NULL);
+
+ if (!performActualUpdate(&updates[0], "1306", dbver))
+ return false;
+ }
+
return true;
}
@@ -36,7 +36,8 @@ RecordingRule::RecordingRule()
m_channelid(0),
m_findday(-1),
m_findtime(QTime::fromString("00:00:00", Qt::ISODate)),
- m_findid(QDate(1970, 1, 1).daysTo(MythDate::current().date()) + 719528),
+ m_findid(QDate(1970, 1, 1).daysTo(MythDate::current().toLocalTime().date())
+ + 719528),
m_type(kNotRecording),
m_searchType(kNoSearch),
m_recPriority(0),
@@ -262,9 +263,10 @@ bool RecordingRule::LoadBySearch(RecSearchType lsearch, QString textname,
m_title = ltitle;
m_subtitle = from;
m_description = forwhat;
- m_findday = (m_startdate.dayOfWeek() + 1) % 7;
+ QDate ldate = MythDate::current().toLocalTime().date();
+ m_findday = (ldate.dayOfWeek() + 1) % 7;
QDate epoch(1970, 1, 1);
- m_findid = epoch.daysTo(m_startdate) + 719528;
+ m_findid = epoch.daysTo(ldate) + 719528;
}
m_loaded = true;
@@ -579,9 +581,10 @@ void RecordingRule::ToMap(InfoMap &infoMap) const
if (m_type == kFindDailyRecord || m_type == kFindWeeklyRecord)
{
- QDateTime dt =
- QDateTime(MythDate::current().date(), m_findtime, Qt::UTC);
- QString findfrom = MythDate::toString(dt, MythDate::kTime);
+ QDateTime ldt =
+ QDateTime(MythDate::current().toLocalTime().date(), m_findtime,
+ Qt::LocalTime);
+ QString findfrom = MythDate::toString(ldt, MythDate::kTime);
if (m_type == kFindWeeklyRecord)
{
int daynum = (m_findday + 5) % 7 + 1;
@@ -703,12 +706,13 @@ void RecordingRule::AssignProgramInfo()
if (m_findday < 0)
{
m_findday =
- (m_progInfo->GetScheduledStartTime().date().dayOfWeek() + 1) % 7;
- m_findtime = m_progInfo->GetScheduledStartTime().time();
+ (m_progInfo->GetScheduledStartTime().toLocalTime().date()
+ .dayOfWeek() + 1) % 7;
+ m_findtime = m_progInfo->GetScheduledStartTime().toLocalTime().time();
QDate epoch(1970, 1, 1);
m_findid = epoch.daysTo(
- m_progInfo->GetScheduledStartTime().date()) + 719528;
+ m_progInfo->GetScheduledStartTime().toLocalTime().date()) + 719528;
}
else
{
@@ -718,7 +722,8 @@ void RecordingRule::AssignProgramInfo()
{
QDate epoch(1970, 1, 1);
m_findid = epoch.daysTo(
- m_progInfo->GetScheduledStartTime().date()) + 719528;
+ m_progInfo->GetScheduledStartTime().toLocalTime().date())
+ + 719528;
}
}
m_category = m_progInfo->GetCategory();
@@ -36,6 +36,7 @@
#include "mythcontext.h"
#include "mythversion.h"
#include "mythdb.h"
+#include "dbutil.h"
#include "exitcodes.h"
#include "compat.h"
#include "storagegroup.h"
@@ -528,6 +529,13 @@ void print_warnings(const MythBackendCommandLineParser &cmdline)
int run_backend(MythBackendCommandLineParser &cmdline)
{
+ if (!DBUtil::CheckTimeZoneSupport())
+ {
+ LOG(VB_GENERAL, LOG_ERR, "MySQL time zone support is not missing. "
+ "Please install it and try again.");
+ return GENERIC_EXIT_DB_NOTIMEZONE;
+ }
+
bool ismaster = gCoreContext->IsMasterHost();
if (!UpgradeTVDatabaseSchema(ismaster, ismaster))
Oops, something went wrong.

0 comments on commit 181641a

Please sign in to comment.