diff --git a/ChangeLog b/ChangeLog
index ef3e2119..f722cafa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2010-10-10  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Retrieve last access time from sqlite3 cookie database.
+	* src/CookieStorage.cc
+	* src/Sqlite3CookieParser.cc
+	* src/Sqlite3CookieParser.h
+	* src/Sqlite3CookieParserImpl.cc
+	* test/Sqlite3CookieParserTest.cc
+	* test/chromium_cookies.sqlite
+	* test/cookies.sqlite
+
 2010-10-10  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Remove expired cookies first when cookies_ is full.
diff --git a/src/CookieStorage.cc b/src/CookieStorage.cc
index b8b3bdb1..a4875267 100644
--- a/src/CookieStorage.cc
+++ b/src/CookieStorage.cc
@@ -308,7 +308,7 @@ bool CookieStorage::load(const std::string& filename, time_t now)
 #ifdef HAVE_SQLITE3
       std::vector<Cookie> cookies;
       try {
-        Sqlite3MozCookieParser(filename).parse(cookies, now);
+        Sqlite3MozCookieParser(filename).parse(cookies);
       } catch(RecoverableException& e) {
         if(logger_->info()) {
           logger_->info(EX_EXCEPTION_CAUGHT, e);
@@ -316,7 +316,7 @@ bool CookieStorage::load(const std::string& filename, time_t now)
                         " Retrying, assuming it is Chromium cookie file.");
         }
         // Try chrome cookie format
-        Sqlite3ChromiumCookieParser(filename).parse(cookies, now);
+        Sqlite3ChromiumCookieParser(filename).parse(cookies);
       }
       storeCookies(cookies.begin(), cookies.end(), now);
 #else // !HAVE_SQLITE3
diff --git a/src/Sqlite3CookieParser.cc b/src/Sqlite3CookieParser.cc
index 81525f8a..088ff99a 100644
--- a/src/Sqlite3CookieParser.cc
+++ b/src/Sqlite3CookieParser.cc
@@ -78,9 +78,23 @@ static std::string toString(const char* str)
   }
 }
 
-static int cookieRowMapper(void* data, int rowIndex,
+static bool parseTime(int64_t& time, const std::string& s)
+{
+  if(!util::parseLLIntNoThrow(time, s)) {
+    return false;
+  }
+  if(sizeof(time_t) == 4 && time > INT32_MAX) {
+    time = INT32_MAX;
+  }
+  return true;
+}
+
+static int cookieRowMapper(void* data, int columns,
                            char** values, char** names)
 {
+  if(columns != 7) {
+    return 0;
+  }
   std::vector<Cookie>& cookies =
     *reinterpret_cast<std::vector<Cookie>*>(data);
   std::string cookieDomain = cookie::removePrecedingDots(toString(values[0]));
@@ -91,13 +105,13 @@ static int cookieRowMapper(void* data, int rowIndex,
     return 0;
   }
   int64_t expiryTime;
-  if(!util::parseLLIntNoThrow(expiryTime, toString(values[3]))) {
+  if(!parseTime(expiryTime, toString(values[3]))) {
     return 0;
   }
-  if(sizeof(time_t) == 4 && expiryTime > INT32_MAX) {
-    expiryTime = INT32_MAX;
+  int64_t lastAccessTime;
+  if(!parseTime(lastAccessTime, toString(values[6]))) {
+    return 0;
   }
-  // TODO get last access, creation date(chrome only)
   Cookie c(cookieName,
            toString(values[5]), // value
            expiryTime,
@@ -107,14 +121,13 @@ static int cookieRowMapper(void* data, int rowIndex,
            cookiePath,
            strcmp(toString(values[2]).c_str(), "1") == 0, //secure
            false,
-           0 // creation time. Set this later.
+           lastAccessTime // creation time. Set this later.
            );
   cookies.push_back(c);
   return 0;
 }
 
-void Sqlite3CookieParser::parse
-(std::vector<Cookie>& cookies, time_t creationTime)
+void Sqlite3CookieParser::parse(std::vector<Cookie>& cookies)
 {
   if(!db_) {
     throw DL_ABORT_EX(StringFormat("SQLite3 database is not opened.").str());
@@ -123,13 +136,6 @@ void Sqlite3CookieParser::parse
   char* sqlite3ErrMsg = 0;
   int ret = sqlite3_exec(db_, getQuery().c_str(), cookieRowMapper,
                          &tcookies, &sqlite3ErrMsg);
-  // TODO If last access, creation date are retrieved from database,
-  // following for loop must be removed.
-  for(std::vector<Cookie>::iterator i = tcookies.begin(), eoi = tcookies.end();
-      i != eoi; ++i) {
-    (*i).setCreationTime(creationTime);
-    (*i).setLastAccessTime(creationTime);
-  }
   std::string errMsg;
   if(sqlite3ErrMsg) {
     errMsg = sqlite3ErrMsg;
diff --git a/src/Sqlite3CookieParser.h b/src/Sqlite3CookieParser.h
index ecf55521..e8679294 100644
--- a/src/Sqlite3CookieParser.h
+++ b/src/Sqlite3CookieParser.h
@@ -55,12 +55,12 @@ public:
   // Loads cookies from sqlite3 database and stores them in cookies.
   // When loading is successful, cookies stored in cookies initially
   // are removed. Otherwise, the content of cookies is unchanged.
-  void parse(std::vector<Cookie>& cookies, time_t creationTime);
+  void parse(std::vector<Cookie>& cookies);
 protected:
   // Returns SQL select statement to get 1 record of cookie.  The sql
   // must return 6 columns in the following order: host, path,
   // secure(1 for secure, 0 for not), expiry(utc, unix time), name,
-  // value
+  // value, last access time(utc, unix time)
   virtual const std::string& getQuery() const = 0;
 private:
   sqlite3* db_;
diff --git a/src/Sqlite3CookieParserImpl.cc b/src/Sqlite3CookieParserImpl.cc
index 9f9ebf56..07fb262c 100644
--- a/src/Sqlite3CookieParserImpl.cc
+++ b/src/Sqlite3CookieParserImpl.cc
@@ -44,7 +44,8 @@ Sqlite3MozCookieParser::~Sqlite3MozCookieParser() {}
 const std::string& Sqlite3MozCookieParser::getQuery() const
 {
   static const std::string sql =
-    "SELECT host, path, isSecure, expiry, name, value FROM moz_cookies";
+    "SELECT host, path, isSecure, expiry, name, value, lastAccessed"
+    " FROM moz_cookies";
   return sql;
 }
 
@@ -56,7 +57,8 @@ Sqlite3ChromiumCookieParser::~Sqlite3ChromiumCookieParser() {}
 const std::string& Sqlite3ChromiumCookieParser::getQuery() const
 {
   static const std::string sql =
-    "SELECT host_key, path, secure, expires_utc, name, value FROM cookies";
+    "SELECT host_key, path, secure, expires_utc, name, value, last_access_utc"
+    " FROM cookies";
   return sql;
 }
 
diff --git a/test/Sqlite3CookieParserTest.cc b/test/Sqlite3CookieParserTest.cc
index e33d1b91..3a87e9ef 100644
--- a/test/Sqlite3CookieParserTest.cc
+++ b/test/Sqlite3CookieParserTest.cc
@@ -35,7 +35,7 @@ void Sqlite3CookieParserTest::testMozParse()
 {
   Sqlite3MozCookieParser parser("cookies.sqlite");
   std::vector<Cookie> cookies;
-  parser.parse(cookies, 0);
+  parser.parse(cookies);
   CPPUNIT_ASSERT_EQUAL((size_t)3, cookies.size());
 
   const Cookie& localhost = cookies[0];
@@ -47,6 +47,8 @@ void Sqlite3CookieParserTest::testMozParse()
   CPPUNIT_ASSERT(localhost.getHostOnly());
   CPPUNIT_ASSERT_EQUAL(std::string("/"), localhost.getPath());
   CPPUNIT_ASSERT(localhost.getSecure());
+  CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost.getLastAccessTime());
+  CPPUNIT_ASSERT_EQUAL((time_t)3000, localhost.getCreationTime());
 
   const Cookie& nullValue = cookies[1];
   CPPUNIT_ASSERT_EQUAL(std::string("uid"), nullValue.getName());
@@ -79,7 +81,7 @@ void Sqlite3CookieParserTest::testMozParse_fileNotFound()
   Sqlite3MozCookieParser parser("fileNotFound");
   try {
     std::vector<Cookie> cookies;
-    parser.parse(cookies, 0);
+    parser.parse(cookies);
     CPPUNIT_FAIL("exception must be thrown.");
   } catch(RecoverableException& e) {
     // SUCCESS
@@ -93,7 +95,7 @@ void Sqlite3CookieParserTest::testMozParse_badfile()
   Sqlite3MozCookieParser parser("badcookies.sqlite");
   try {
     std::vector<Cookie> cookies;
-    parser.parse(cookies, 0);
+    parser.parse(cookies);
     CPPUNIT_FAIL("exception must be thrown.");
   } catch(RecoverableException& e) {
     // SUCCESS
@@ -104,7 +106,7 @@ void Sqlite3CookieParserTest::testChromumParse()
 {
   Sqlite3ChromiumCookieParser parser("chromium_cookies.sqlite");
   std::vector<Cookie> cookies;
-  parser.parse(cookies, 0);
+  parser.parse(cookies);
   CPPUNIT_ASSERT_EQUAL((size_t)3, cookies.size());
 
   const Cookie& sfnet = cookies[0];
@@ -130,7 +132,9 @@ void Sqlite3CookieParserTest::testChromumParse()
 
   const Cookie& localnet = cookies[2];
   CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), localnet.getDomain());
-  CPPUNIT_ASSERT(sfjp.getHostOnly());  
+  CPPUNIT_ASSERT(sfjp.getHostOnly());
+  CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet.getLastAccessTime());
+  CPPUNIT_ASSERT_EQUAL((time_t)3000, localnet.getCreationTime());
 }
 
 } // namespace aria2
diff --git a/test/chromium_cookies.sqlite b/test/chromium_cookies.sqlite
index 6956987d..c3e98fc8 100644
Binary files a/test/chromium_cookies.sqlite and b/test/chromium_cookies.sqlite differ
diff --git a/test/cookies.sqlite b/test/cookies.sqlite
index 8a52a10c..e21fa95d 100644
Binary files a/test/cookies.sqlite and b/test/cookies.sqlite differ