]> git.saurik.com Git - apt.git/commitdiff
use +0000 instead of UTC by default as timezone in output
authorDavid Kalnischkies <david@kalnischkies.de>
Sat, 2 Jul 2016 09:28:42 +0000 (11:28 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Sat, 2 Jul 2016 10:01:17 +0000 (12:01 +0200)
All apt versions support numeric as well as 3-character timezones just
fine and its actually hard to write code which doesn't "accidently"
accepts it. So why change? Documenting the Date/Valid-Until fields in
the Release file is easy to do in terms of referencing the
datetime format used e.g. in the Debian changelogs (policy ยง4.4). This
format specifies only the numeric timezones through, not the nowadays
obsolete 3-character ones, so in the interest of least surprise we should
use the same format even through it carries a small risk of regression
in other clients (which encounter repositories created with
apt-ftparchive).

In case it is really regressing in practice, the hidden option
  -o APT::FTPArchive::Release::NumericTimezone=0
can be used to go back to good old UTC as timezone.

The EDSP and EIPP protocols use this 'new' format, the text interface
used to communicate with the acquire methods does not for compatibility
reasons even if none of our methods would be effected and I doubt any
other would (in these instances the timezone is 'GMT' as that is what
HTTP/1.1 requires). Note that this is only true for apt talking to
methods, (libapt-based) methods talking to apt will respond with the
'new' format.  It is therefore strongly adviced to support both also in
method input.

13 files changed:
apt-pkg/acquire-item.cc
apt-pkg/acquire-method.cc
apt-pkg/contrib/strutl.cc
apt-pkg/contrib/strutl.h
apt-pkg/edsp.cc
cmdline/apt-cache.cc
doc/external-dependency-solver-protocol.txt
doc/external-installation-planner-protocol.txt
ftparchive/writer.cc
methods/http.cc
methods/https.cc
test/integration/framework
test/interactive-helper/aptwebserver.cc

index 5ae9229d9ff05e31e32db99cf4fde1f05e802a92..71cb18811506a129e058d0d052a005d9b2cd1f44 100644 (file)
@@ -1167,7 +1167,7 @@ string pkgAcqMetaBase::Custom600Headers() const
    string const FinalFile = GetFinalFilename();
    struct stat Buf;
    if (stat(FinalFile.c_str(),&Buf) == 0)
    string const FinalFile = GetFinalFilename();
    struct stat Buf;
    if (stat(FinalFile.c_str(),&Buf) == 0)
-      Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
+      Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime, false);
 
    return Header;
 }
 
    return Header;
 }
@@ -1916,7 +1916,7 @@ void pkgAcqBaseIndex::Failed(std::string const &Message,pkgAcquire::MethodConfig
    if (timespec == 0)
       ErrorText.append("<unknown>");
    else
    if (timespec == 0)
       ErrorText.append("<unknown>");
    else
-      ErrorText.append(TimeRFC1123(timespec));
+      ErrorText.append(TimeRFC1123(timespec, true));
    ErrorText.append("\n");
 }
                                                                        /*}}}*/
    ErrorText.append("\n");
 }
                                                                        /*}}}*/
@@ -1969,7 +1969,7 @@ string pkgAcqDiffIndex::Custom600Headers() const
    if (stat(Final.c_str(),&Buf) != 0)
       return "\nIndex-File: true";
    
    if (stat(Final.c_str(),&Buf) != 0)
       return "\nIndex-File: true";
    
-   return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
+   return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime, false);
 }
                                                                        /*}}}*/
 void pkgAcqDiffIndex::QueueOnIMSHit() const                            /*{{{*/
 }
                                                                        /*}}}*/
 void pkgAcqDiffIndex::QueueOnIMSHit() const                            /*{{{*/
@@ -2881,7 +2881,7 @@ string pkgAcqIndex::Custom600Headers() const
 
       struct stat Buf;
       if (stat(Final.c_str(),&Buf) == 0)
 
       struct stat Buf;
       if (stat(Final.c_str(),&Buf) == 0)
-        msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
+        msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime, false);
    }
 
    if(Target.IsOptional)
    }
 
    if(Target.IsOptional)
index 82f4b626d08486fe32091105a3fda3470975de7d..a9fff661b49fe08741287fa2d9d09111f17ba857 100644 (file)
@@ -148,7 +148,7 @@ void pkgAcqMethod::URIStart(FetchResult &Res)
       std::cout << "Size: " << std::to_string(Res.Size) << "\n";
 
    if (Res.LastModified != 0)
       std::cout << "Size: " << std::to_string(Res.Size) << "\n";
 
    if (Res.LastModified != 0)
-      std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
+      std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified, true) << "\n";
 
    if (Res.ResumePoint != 0)
       std::cout << "Resume-Point: " << std::to_string(Res.ResumePoint) << "\n";
 
    if (Res.ResumePoint != 0)
       std::cout << "Resume-Point: " << std::to_string(Res.ResumePoint) << "\n";
@@ -187,7 +187,7 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
       std::cout << "Size: " << std::to_string(Res.Size) << "\n";
 
    if (Res.LastModified != 0)
       std::cout << "Size: " << std::to_string(Res.Size) << "\n";
 
    if (Res.LastModified != 0)
-      std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
+      std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified, true) << "\n";
 
    printHashStringList(&Res.Hashes);
 
 
    printHashStringList(&Res.Hashes);
 
@@ -216,7 +216,7 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
         std::cout << "Alt-Size: " << std::to_string(Alt->Size) << "\n";
 
       if (Alt->LastModified != 0)
         std::cout << "Alt-Size: " << std::to_string(Alt->Size) << "\n";
 
       if (Alt->LastModified != 0)
-        std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
+        std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified, true) << "\n";
 
       printHashStringList(&Alt->Hashes);
 
 
       printHashStringList(&Alt->Hashes);
 
index d0bc938e44c6adad5b3449e266c24b6d21b888bc..7b6bb28541bb17a986e855ecec20916e7f29cbea 100644 (file)
@@ -749,6 +749,10 @@ int StringToBool(const string &Text,int Default)
 /* This converts a time_t into a string time representation that is
    year 2000 complient and timezone neutral */
 string TimeRFC1123(time_t Date)
 /* This converts a time_t into a string time representation that is
    year 2000 complient and timezone neutral */
 string TimeRFC1123(time_t Date)
+{
+   return TimeRFC1123(Date, false);
+}
+string TimeRFC1123(time_t Date, bool const NumericTimezone)
 {
    struct tm Conv;
    if (gmtime_r(&Date, &Conv) == NULL)
 {
    struct tm Conv;
    if (gmtime_r(&Date, &Conv) == NULL)
@@ -757,10 +761,14 @@ string TimeRFC1123(time_t Date)
    auto const posix = std::locale("C.UTF-8");
    std::ostringstream datestr;
    datestr.imbue(posix);
    auto const posix = std::locale("C.UTF-8");
    std::ostringstream datestr;
    datestr.imbue(posix);
-   APT::StringView const fmt("%a, %d %b %Y %H:%M:%S GMT");
+   APT::StringView const fmt("%a, %d %b %Y %H:%M:%S");
    std::use_facet<std::time_put<char>>(posix).put(
                     std::ostreambuf_iterator<char>(datestr),
                     datestr, ' ', &Conv, fmt.data(), fmt.data() + fmt.size());
    std::use_facet<std::time_put<char>>(posix).put(
                     std::ostreambuf_iterator<char>(datestr),
                     datestr, ' ', &Conv, fmt.data(), fmt.data() + fmt.size());
+   if (NumericTimezone)
+      datestr << " +0000";
+   else
+      datestr << " GMT";
    return datestr.str();
 }
                                                                        /*}}}*/
    return datestr.str();
 }
                                                                        /*}}}*/
index a32aaf06d06a95fe8fac3cba613faed65ad6a6ee..f3591d65feb5d2c049f67d2ca4b7618061e80291 100644 (file)
@@ -66,7 +66,17 @@ std::string TimeToStr(unsigned long Sec);
 std::string Base64Encode(const std::string &Str);
 std::string OutputInDepth(const unsigned long Depth, const char* Separator="  ");
 std::string URItoFileName(const std::string &URI);
 std::string Base64Encode(const std::string &Str);
 std::string OutputInDepth(const unsigned long Depth, const char* Separator="  ");
 std::string URItoFileName(const std::string &URI);
-std::string TimeRFC1123(time_t Date);
+APT_DEPRECATED_MSG("Specify if GMT is required or a numeric timezone can be used") std::string TimeRFC1123(time_t Date);
+/** returns a datetime string as needed by HTTP/1.1 and Debian files.
+ *
+ * Note: The date will always be represented in a UTC timezone
+ *
+ * @param Date to be represented as a string
+ * @param NumericTimezone is preferred in general, but HTTP/1.1 requires the use
+ *    of GMT as timezone instead. \b true means that the timezone should be denoted
+ *    as "+0000" while \b false uses "GMT".
+ */
+std::string TimeRFC1123(time_t Date, bool const NumericTimezone);
 /** parses time as needed by HTTP/1.1 and Debian files.
  *
  * HTTP/1.1 prefers dates in RFC1123 format (but the other two obsolete date formats
 /** parses time as needed by HTTP/1.1 and Debian files.
  *
  * HTTP/1.1 prefers dates in RFC1123 format (but the other two obsolete date formats
index 55bc0fcbdefc993e7c02fad89c2a50f5bb3ea2cf..27b269fd21cbf5cec6c066e279dc53566e15beeb 100644 (file)
@@ -911,14 +911,14 @@ bool EDSP::WriteSolutionStanza(FileFd &output, char const * const Type, pkgCache
                                                                        /*}}}*/
 // EDSP::WriteProgess - pulse to the given file descriptor             /*{{{*/
 bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
                                                                        /*}}}*/
 // EDSP::WriteProgess - pulse to the given file descriptor             /*{{{*/
 bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
-       fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
+       fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL), true).c_str());
        fprintf(output, "Percentage: %d\n", percent);
        fprintf(output, "Message: %s\n\n", message);
        fflush(output);
        return true;
 }
 bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FileFd &output) {
        fprintf(output, "Percentage: %d\n", percent);
        fprintf(output, "Message: %s\n\n", message);
        fflush(output);
        return true;
 }
 bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FileFd &output) {
-       return WriteOkay(output, "Progress: ", TimeRFC1123(time(NULL)), "\n",
+       return WriteOkay(output, "Progress: ", TimeRFC1123(time(NULL), true), "\n",
              "Percentage: ", percent, "\n",
              "Message: ", message, "\n\n") && output.Flush();
 }
              "Percentage: ", percent, "\n",
              "Message: ", message, "\n\n") && output.Flush();
 }
index 6153f0e49d03fd79840cc9c57090c2adad3e96fd..0d7425c48468bd41defa9b109f1ee6a276a810e9 100644 (file)
@@ -380,7 +380,7 @@ static bool Dump(CommandLine &)
       std::cout << " Size: " << F->Size << std::endl;
       std::cout << " ID: " << F->ID << std::endl;
       std::cout << " Flags: " << F->Flags << std::endl;
       std::cout << " Size: " << F->Size << std::endl;
       std::cout << " ID: " << F->ID << std::endl;
       std::cout << " Flags: " << F->Flags << std::endl;
-      std::cout << " Time: " << TimeRFC1123(F->mtime) << std::endl;
+      std::cout << " Time: " << TimeRFC1123(F->mtime, true) << std::endl;
       std::cout << " Archive: " << DeNull(F.Archive()) << std::endl;
       std::cout << " Component: " << DeNull(F.Component()) << std::endl;
       std::cout << " Version: " << DeNull(F.Version()) << std::endl;
       std::cout << " Archive: " << DeNull(F.Archive()) << std::endl;
       std::cout << " Component: " << DeNull(F.Component()) << std::endl;
       std::cout << " Version: " << DeNull(F.Version()) << std::endl;
index 45221260289d20f832fd5907fc04f0dfda264d41..56689066539e71c1e3218c0aeaf081bdbb17e88b 100644 (file)
@@ -352,8 +352,9 @@ information to APT using **progress stanzas**. A progress stanza starts
 with the Progress field and might contain the following fields:
 
 - **Progress:** (mandatory). The value of this field is a date and time
 with the Progress field and might contain the following fields:
 
 - **Progress:** (mandatory). The value of this field is a date and time
-  timestamp, in RFC 2822 format. The timestamp provides a time
-  annotation for the progress report.
+  timestamp from the UTC timezone, in RFC 2822 format (see 'date -uR' as
+  an example). The timestamp provides a time annotation for the
+  progress report.
 
 - **Percentage:** (optional). An integer from 0 to 100, representing the
   completion of the dependency solving process, as declared by the
 
 - **Percentage:** (optional). An integer from 0 to 100, representing the
   completion of the dependency solving process, as declared by the
index 319d139c6e3dd806d2ab7bb32846dab4cd5a7774..44fa8ff5370d56de8405bb366a8690d0039d498f 100644 (file)
@@ -280,8 +280,9 @@ information to APT using **progress stanzas**. A progress stanza starts
 with the Progress field and might contain the following fields:
 
 - **Progress:** (mandatory). The value of this field is a date and time
 with the Progress field and might contain the following fields:
 
 - **Progress:** (mandatory). The value of this field is a date and time
-  timestamp, in RFC 2822 format. The timestamp provides a time
-  annotation for the progress report.
+  timestamp from the UTC timezone, in RFC 2822 format (see 'date -uR' as
+  an example). The timestamp provides a time annotation for the
+  progress report.
 
 - **Percentage:** (optional). An integer from 0 to 100, representing the
   completion of the installation planning process, as declared by the
 
 - **Percentage:** (optional). An integer from 0 to 100, representing the
   completion of the installation planning process, as declared by the
index dbeaa16a6a0b446151697c403118c1cc69096037..c34a04d1a387d225184bfced5d79a2ec3bdfd33b 100644 (file)
@@ -969,11 +969,15 @@ bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompres
 /* */
 static std::string formatUTCDateTime(time_t const now)
 {
 /* */
 static std::string formatUTCDateTime(time_t const now)
 {
+   bool const NumericTimezone = _config->FindB("APT::FTPArchive::Release::NumericTimezone", true);
    // TimeRFC1123 uses GMT to satisfy HTTP/1.1
    // TimeRFC1123 uses GMT to satisfy HTTP/1.1
-   std::string datetime = TimeRFC1123(now);
-   auto const lastspace = datetime.rfind(' ');
-   if (likely(lastspace != std::string::npos))
-      datetime.replace(lastspace + 1, 3, "UTC");
+   std::string datetime = TimeRFC1123(now, NumericTimezone);
+   if (NumericTimezone == false)
+   {
+      auto const lastspace = datetime.rfind(' ');
+      if (likely(lastspace != std::string::npos))
+        datetime.replace(lastspace + 1, 3, "UTC");
+   }
    return datetime;
 }
 ReleaseWriter::ReleaseWriter(FileFd * const GivenOutput, string const &/*DB*/) : FTWScanner(GivenOutput)
    return datetime;
 }
 ReleaseWriter::ReleaseWriter(FileFd * const GivenOutput, string const &/*DB*/) : FTWScanner(GivenOutput)
index fc54ece3ad2c42155d458ded77d991964751fd66..a283162a2e2905700fe5793fa78d9811cf87826d 100644 (file)
@@ -737,9 +737,9 @@ void HttpMethod::SendReq(FetchItem *Itm)
    struct stat SBuf;
    if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
       Req << "Range: bytes=" << SBuf.st_size << "-\r\n"
    struct stat SBuf;
    if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
       Req << "Range: bytes=" << SBuf.st_size << "-\r\n"
-        << "If-Range: " << TimeRFC1123(SBuf.st_mtime) << "\r\n";
+        << "If-Range: " << TimeRFC1123(SBuf.st_mtime, false) << "\r\n";
    else if (Itm->LastModified != 0)
    else if (Itm->LastModified != 0)
-      Req << "If-Modified-Since: " << TimeRFC1123(Itm->LastModified).c_str() << "\r\n";
+      Req << "If-Modified-Since: " << TimeRFC1123(Itm->LastModified, false).c_str() << "\r\n";
 
    if (Server->Proxy.User.empty() == false || Server->Proxy.Password.empty() == false)
       Req << "Proxy-Authorization: Basic "
 
    if (Server->Proxy.User.empty() == false || Server->Proxy.Password.empty() == false)
       Req << "Proxy-Authorization: Basic "
index 35992ee966c227767de31b0e7394284d82778a8c..92f786d1706d6e21da3de9c5dd09f6bad37077de 100644 (file)
@@ -388,7 +388,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
       std::string Buf;
       strprintf(Buf, "Range: bytes=%lli-", (long long) SBuf.st_size);
       headers = curl_slist_append(headers, Buf.c_str());
       std::string Buf;
       strprintf(Buf, "Range: bytes=%lli-", (long long) SBuf.st_size);
       headers = curl_slist_append(headers, Buf.c_str());
-      strprintf(Buf, "If-Range: %s", TimeRFC1123(SBuf.st_mtime).c_str());
+      strprintf(Buf, "If-Range: %s", TimeRFC1123(SBuf.st_mtime, false).c_str());
       headers = curl_slist_append(headers, Buf.c_str());
    }
    else if(Itm->LastModified > 0)
       headers = curl_slist_append(headers, Buf.c_str());
    }
    else if(Itm->LastModified > 0)
index 8ca878148743c2add20ca3850165ad084cb42979..4aa89cf203f8c848ddc9e1d6a4bce93a2dd47f37 100644 (file)
@@ -219,10 +219,10 @@ gdb() {
        runapt command gdb --quiet -ex run "$CMD" --args "$CMD" "$@"
 }
 lastmodification() {
        runapt command gdb --quiet -ex run "$CMD" --args "$CMD" "$@"
 }
 lastmodification() {
-       date -u -d "@$(stat -c '%Y' "${TMPWORKINGDIRECTORY}/$1")" '+%a, %d %b %Y %H:%M:%S GMT'
+       date -u -d "@$(stat -c '%Y' "${TMPWORKINGDIRECTORY}/$1")" -R
 }
 releasefiledate() {
 }
 releasefiledate() {
-       grep "^${2:-Date}:" "$1" | cut -d' ' -f 2- | sed -e 's#UTC#GMT#'
+       grep "^${2:-Date}:" "$1" | cut -d' ' -f 2-
 }
 
 exitwithstatus() {
 }
 
 exitwithstatus() {
@@ -1016,13 +1016,13 @@ NotAutomatic: yes' "$dir/Release"
        fi
        if [ -n "$DATE" -a "$DATE" != "now" ]; then
                for release in $(find ./aptarchive -name 'Release'); do
        fi
        if [ -n "$DATE" -a "$DATE" != "now" ]; then
                for release in $(find ./aptarchive -name 'Release'); do
-                       sed -i "s/^Date: .*$/Date: $(date -u -d "$DATE" '+%a, %d %b %Y %H:%M:%S %Z')/" "$release"
+                       sed -i "s/^Date: .*$/Date: $(date -u -d "$DATE" -R)/" "$release"
                        touch -d "$DATE" "$release"
                done
        fi
        if [ -n "$VALIDUNTIL" ]; then
                sed -i "/^Date: / a\
                        touch -d "$DATE" "$release"
                done
        fi
        if [ -n "$VALIDUNTIL" ]; then
                sed -i "/^Date: / a\
-Valid-Until: $(date -u -d "$VALIDUNTIL" '+%a, %d %b %Y %H:%M:%S %Z')" $(find ./aptarchive -name 'Release')
+Valid-Until: $(date -u -d "$VALIDUNTIL" -R)" $(find ./aptarchive -name 'Release')
        fi
        msgdone "info"
 }
        fi
        msgdone "info"
 }
@@ -1154,7 +1154,7 @@ signreleasefiles() {
 }
 
 redatereleasefiles() {
 }
 
 redatereleasefiles() {
-       local DATE="$(date -u -d "$1" '+%a, %d %b %Y %H:%M:%S %Z')"
+       local DATE="$(date -u -d "$1" -R)"
        for release in $(find aptarchive/ -name 'Release'); do
                sed -i "s/^Date: .*$/Date: ${DATE}/" "$release"
                touch -d "$DATE" "$release"
        for release in $(find aptarchive/ -name 'Release'); do
                sed -i "s/^Date: .*$/Date: ${DATE}/" "$release"
                touch -d "$DATE" "$release"
index 3e91406abdbbc98e9f49a2497a662d48294ccb58..817760ec309e57ecbe1c072d4c98a5b71ab19b56 100644 (file)
@@ -99,7 +99,7 @@ static void addFileHeaders(std::list<std::string> &headers, FileFd &data)/*{{{*/
    if (_config->FindB("aptwebserver::support::last-modified", true) == true)
    {
       std::string lastmodified("Last-Modified: ");
    if (_config->FindB("aptwebserver::support::last-modified", true) == true)
    {
       std::string lastmodified("Last-Modified: ");
-      lastmodified.append(TimeRFC1123(data.ModificationTime()));
+      lastmodified.append(TimeRFC1123(data.ModificationTime(), false));
       headers.push_back(lastmodified);
    }
 }
       headers.push_back(lastmodified);
    }
 }
@@ -128,7 +128,7 @@ static bool sendHead(int const client, int const httpcode, std::list<std::string
       headers.push_back(*h);
 
    std::string date("Date: ");
       headers.push_back(*h);
 
    std::string date("Date: ");
-   date.append(TimeRFC1123(time(NULL)));
+   date.append(TimeRFC1123(time(NULL), false));
    headers.push_back(date);
 
    if (chunkedTransferEncoding(headers) == true)
    headers.push_back(date);
 
    if (chunkedTransferEncoding(headers) == true)
@@ -359,7 +359,7 @@ static void sendDirectoryListing(int const client, std::string const &dir,/*{{{*
                 << "<td><a href=\"" << namelist[i]->d_name << "\">" << namelist[i]->d_name << "</a></td>"
                 << "<td>" << SizeToStr(fs.st_size) << "B</td>";
       }
                 << "<td><a href=\"" << namelist[i]->d_name << "\">" << namelist[i]->d_name << "</a></td>"
                 << "<td>" << SizeToStr(fs.st_size) << "B</td>";
       }
-      listing << "<td>" << TimeRFC1123(fs.st_mtime) << "</td></tr>" << std::endl;
+      listing << "<td>" << TimeRFC1123(fs.st_mtime, true) << "</td></tr>" << std::endl;
    }
    listing << "</table></body></html>" << std::endl;
 
    }
    listing << "</table></body></html>" << std::endl;