lichess.org
Donate

Query: How is Time spent playing on profile calculated

Hello,
How is the "The Time spent playing" calculated :
My profile says 22 days, 13 hours and 44 minutes. when I download my PGN files I find the UTC time only and not UTC End time.
How can we exactly calculate the end time? ( all I know if the UTC start time and game duration for example 5+1 ) - from this how can we precisely derive how long have I played?
Thanks in advance.
request:

curl "lichess.org/api/games/user/lishadowapps?max=1" -H "Accept: application/x-ndjson"

response:

{"id":"yNFRBVc4","rated":true,"variant":"atomic","speed":"rapid","perf":"atomic","createdAt":1579519705716,"lastMoveAt":1579520292314,"status":"resign","players":{"white":{"user":{"id":"ceres222","name":"ceres222"},"rating":2057,"ratingDiff":8},"black":{"user":{"id":"lishadowapps","name":"lishadowapps"},"rating":2221,"ratingDiff":-8}},"winner":"white","moves":"e3 e6 Nf3 f5 Ne5 d5 Nd7 Bb4 c3 Qh4 g3 Nf6 f3 Ne4 fxe4 Qg4 Qxg4 Nc6 d4 b6 Ba6 Bxa6 O-O Ne5 dxe5 O-O-O cxb4 g5 b4 c6 Bb2 e5 b5 h5 Ba3 Rh6 Be7 Re8 Bxg5 h4 Rc1 Rg8 Nf6","tournament":"Osax2LaF","clock":{"initial":300,"increment":10,"totalTime":700}}

"lastMoveAt":1579520292314

If you go to www.epochconverter.com/ and convert time stamp 1579520292314, you get:

GMT: 2020. January 20., Monday 11:38:12.314

To calculate game duration in milliseconds use lastMoveAt - createdAt.

It is a new feature of the API that you can include the PGN in the JSON representation, by the query parameter pgnInJson=true. So the JSON representation is strictly more powerful than the PGN representation.

request with pgnInJson:

curl "lichess.org/api/games/user/lishadowapps?max=1&pgnInJson=true" -H "Accept: application/x-ndjson"

response with pgnInJson:

{"id":"yNFRBVc4","rated":true,"variant":"atomic","speed":"rapid","perf":"atomic","createdAt":1579519705716,"lastMoveAt":1579520292314,"status":"resign","players":{"white":{"user":{"id":"ceres222","name":"ceres222"},"rating":2057,"ratingDiff":8},"black":{"user":{"id":"lishadowapps","name":"lishadowapps"},"rating":2221,"ratingDiff":-8}},"winner":"white","moves":"e3 e6 Nf3 f5 Ne5 d5 Nd7 Bb4 c3 Qh4 g3 Nf6 f3 Ne4 fxe4 Qg4 Qxg4 Nc6 d4 b6 Ba6 Bxa6 O-O Ne5 dxe5 O-O-O cxb4 g5 b4 c6 Bb2 e5 b5 h5 Ba3 Rh6 Be7 Re8 Bxg5 h4 Rc1 Rg8 Nf6","pgn":"[Event \"Atomic Rapid Team Battle\"]\n[Site \"lichess.org/yNFRBVc4\"]\n[Date \"2020.01.20\"]\n[Round \"-\"]\n[White \"ceres222\"]\n[Black \"lishadowapps\"]\n[Result \"1-0\"]\n[UTCDate \"2020.01.20\"]\n[UTCTime \"11:28:25\"]\n[WhiteElo \"2057\"]\n[BlackElo \"2221\"]\n[WhiteRatingDiff \"+8\"]\n[BlackRatingDiff \"-8\"]\n[Variant \"Atomic\"]\n[TimeControl \"300+10\"]\n[ECO \"?\"]\n[Termination \"Normal\"]\n\n1. e3 e6 2. Nf3 f5 3. Ne5 d5 4. Nd7 Bb4 5. c3 Qh4 6. g3 Nf6 7. f3 Ne4 8. fxe4 Qg4 9. Qxg4 Nc6 10. d4 b6 11. Ba6 Bxa6 12. O-O Ne5 13. dxe5 O-O-O 14. cxb4 g5 15. b4 c6 16. Bb2 e5 17. b5 h5 18. Ba3 Rh6 19. Be7 Re8 20. Bxg5 h4 21. Rc1 Rg8 22. Nf6 1-0\n\n\n","tournament":"Osax2LaF","clock":{"initial":300,"increment":10,"totalTime":700}}

As pgnInJson has the game url, it was resolved in the post to a chess board.
Thanks @lishadowapps. I ran the query you have given , is the api deprecated?
Also is the information found in the PGN file database.lichess.org ( I don't find it there).
Responses to the query below.
curl "lichess.org/api/games/user/lishadowapps?max=1" -H "Accept: application/x-ndjson"
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
curl "lichess.org/api/games/user/lishadowapps?max=1&pgnInJson=true" -H "Accept: application/x-ndjson"
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
The request in the OP was a fresh one. Now I also get this "301 Moved Permanently" status which is strange and I have never experienced it before.

As I said the JSON is more powerful than the PGN and in the database you only have the PGN. So only from the database, you cannot reconstruct game duration.

You have to make an API request to obtain the JSON.

Request to obtain JSON of a single game:

curl "lichess.org/game/export/yNFRBVc4" -H "Accept: application/json"

response:

{"id":"yNFRBVc4","rated":true,"variant":"atomic","speed":"rapid","perf":"atomic","createdAt":1579519705716,"lastMoveAt":1579520292314,"status":"resign","players":{"white":{"user":{"id":"ceres222","name":"ceres222"},"rating":2057,"ratingDiff":8},"black":{"user":{"id":"lishadowapps","name":"lishadowapps"},"rating":2221,"ratingDiff":-8}},"winner":"white","moves":"e3 e6 Nf3 f5 Ne5 d5 Nd7 Bb4 c3 Qh4 g3 Nf6 f3 Ne4 fxe4 Qg4 Qxg4 Nc6 d4 b6 Ba6 Bxa6 O-O Ne5 dxe5 O-O-O cxb4 g5 b4 c6 Bb2 e5 b5 h5 Ba3 Rh6 Be7 Re8 Bxg5 h4 Rc1 Rg8 Nf6","tournament":"Osax2LaF","clock":{"initial":300,"increment":10,"totalTime":700}}

You can make a batch request with up to 300 game ids at once.

Request to obtain up to 300 games ( 2 games for now ):

curl -X POST "lichess.org/games/export/_ids" -d "yNFRBVc4,twK6DTs3" -H "Accept: application/x-ndjson"

response:

{"id":"yNFRBVc4","rated":true,"variant":"atomic","speed":"rapid","perf":"atomic","createdAt":1579519705716,"lastMoveAt":1579520292314,"status":"resign","players":{"white":{"user":{"id":"ceres222","name":"ceres222"},"rating":2057,"ratingDiff":8},"black":{"user":{"id":"lishadowapps","name":"lishadowapps"},"rating":2221,"ratingDiff":-8}},"winner":"white","moves":"e3 e6 Nf3 f5 Ne5 d5 Nd7 Bb4 c3 Qh4 g3 Nf6 f3 Ne4 fxe4 Qg4 Qxg4 Nc6 d4 b6 Ba6 Bxa6 O-O Ne5 dxe5 O-O-O cxb4 g5 b4 c6 Bb2 e5 b5 h5 Ba3 Rh6 Be7 Re8 Bxg5 h4 Rc1 Rg8 Nf6","tournament":"Osax2LaF","clock":{"initial":300,"increment":10,"totalTime":700}}
{"id":"twK6DTs3","rated":true,"variant":"atomic","speed":"rapid","perf":"atomic","createdAt":1579518661274,"lastMoveAt":1579519193201,"status":"mate","players":{"white":{"user":{"id":"hyperion_chess","name":"Hyperion_Chess"},"rating":2077,"ratingDiff":-4},"black":{"user":{"id":"lishadowapps","name":"lishadowapps"},"rating":2217,"ratingDiff":4}},"winner":"black","moves":"e3 e6 Nf3 f5 Ne5 d5 h4 Bb4 c3 Nf6 Nf7 O-O Qh5 Nxh5 Nxd8 f4 f3 e5 d4 e4 Ba6 bxa6 O-O g5 Na3 Bxa3 exf4 Nd7 Bxg5 e3 f4 e2 Rfe1 Nf6 f5 Kf7 g4 Nxg4 f6 Rg8+ Kh2 Rg2+ Kh1 Rh2+ Kg1 Rg8#","tournament":"Osax2LaF","clock":{"initial":300,"increment":10,"totalTime":700}}
Solution to the 301 problem:

request:

curl "lichess.org/api/games/user/lishadowapps?max=1" -H "Accept: application/x-ndjson" -L

response:

{"id":"yNFRBVc4","rated":true,"variant":"atomic","speed":"rapid","perf":"atomic","createdAt":1579519705716,"lastMoveAt":1579520292314,"status":"resign","players":{"white":{"user":{"id":"ceres222","name":"ceres222"},"rating":2057,"ratingDiff":8},"black":{"user":{"id":"lishadowapps","name":"lishadowapps"},"rating":2221,"ratingDiff":-8}},"winner":"white","moves":"e3 e6 Nf3 f5 Ne5 d5 Nd7 Bb4 c3 Qh4 g3 Nf6 f3 Ne4 fxe4 Qg4 Qxg4 Nc6 d4 b6 Ba6 Bxa6 O-O Ne5 dxe5 O-O-O cxb4 g5 b4 c6 Bb2 e5 b5 h5 Ba3 Rh6 Be7 Re8 Bxg5 h4 Rc1 Rg8 Nf6","tournament":"Osax2LaF","clock":{"initial":300,"increment":10,"totalTime":700}}

Note that I used the flag "-L" to follow redirects.
Thanks a lot @lishadowapps . The -:L option worked . Brilliant!!
Thanks so much for the response, Just a final question : as part of this query we get last 300 games , is there anyway we can get more games than that? preferably entire history. Also , like the pgn history is stored in database.lichess.org is there any place where the json data is stored? like json.lichess.org :-).
Not the last 300 games, rather the games by ids listed in the POST body separated by comma:

curl -X POST "lichess.org/games/export/_ids" -d "yNFRBVc4,twK6DTs3" -H "Accept: application/x-ndjson"

note that:

-d "yNFRBVc4,twK6DTs3"

stands for give me games by id "yNFRBVc4" and by id "twK6DTs3";

You can obtain the game id from the PGN "Site" header:

[Site "lichess.org/...gameid..."]

I don't think there is a JSON database.
Question what is the significant of Total time "clock":{"initial":120,"increment":1,"totalTime":160}} ?
Question 2: There seems to be some overhead when I analyze the Difference (lastMoveAt - createdAt) and derive the total time played.
Below are description of two matches ( Match 1 Blitz 1+0 ) and ( Match2: Blitz 2+1)
Description :
Match 1 : curl "lichess.org/game/export/B9JiYVmp" -H "Accept: application/json" -L
"createdAt" :1580189175707 Tuesday, January 28, 2020 5:26:15.707 AM
"lastMoveAt":1580189564679 Tuesday, January 28, 2020 5:32:44.679 AM
Difference lastMoveAt - createdAt = 388972 = 388.972 = 6 Minutes 28 seconds
( from the website - time remaining is 10 sec for white and 15 sec for white )
Total moves played = 73
Total time played = (120 -10) + 73*1 + (120 -15) +73*1 = 183+ 178 = 361 Seconds.
( Which is 17 seconds less than lastMoveAt - createdAt time)
Expectation : Should be 6 minutes and 28 seconds - but it is 17 seconds extra

Match 2 : curl "lichess.org/game/export/o2h1NfVO" -H "Accept: application/json" -L
Played 1+0 Blitz ; After game the remaining time for white and black was almost zero
Analysis:
"createdAt":1580186635120,GMT: Tuesday, January 28, 2020 4:43:55.120 AM
"lastMoveAt":1580186768568 Tuesday, January 28, 2020 4:46:08.568 AM
Difference lastMoveAt - createdAt = 133448 = ( 133.448 sec ) 2 Minutes and 13 seconds
Expectation : Difference should be 120 sec ( exactly 2 minutes) since no increment.

There is a difference between createdAt and the should be existing field "firstMoveAt". A game is created when a seek is accepted or there is a lobby or tourney auto pairing. Then players have some time to make their first move. So the game duration would be lastMoveAt - firstMoveAt, however this information is not directly available in the API ( even this can be questioned, because the game can go on for a while after the last move was made and the other player has time on their clock, so we would really need a "terminatedAt" field and the absolutely precise duration could be calculated as terminatedAt - firstMoveAt ).

The best you can do is either query the PGN or the JSON with pgnInJson with clocks=true set, and consider the clock times.

curl "lichess.org/game/export/o2h1NfVO?clocks=true" -H "Accept: application/x-chess-pgn" -L

...

1. e4 { [%clk 0:01:00] } d5 { [%clk 0:01:00] } 2. exd5 { [%clk 0:00:57] } Qxd5 { [%clk 0:01:00] } 3. d4 { [%clk 0:00:56] } Qd8 { [%clk 0:01:00] } 4. Nc3 { [%clk 0:00:55] } Nc6 { [%clk 0:00:59] } 5. Nf3 { [%clk 0:00:51] } Bf5 { [%clk 0:00:58] } 6. Bf4 { [%clk 0:00:49] } Nb4 { [%clk 0:00:57] } 7. Bd3 { [%clk 0:00:44] } Bxd3 { [%clk 0:00:56] } 8. cxd3 { [%clk 0:00:44] } f6 { [%clk 0:00:51] } 9. O-O { [%clk 0:00:43] } e5 { [%clk 0:00:50] } 10. dxe5 { [%clk 0:00:40] } fxe5 { [%clk 0:00:50] } 11. Nxe5 { [%clk 0:00:38] } Bd6 { [%clk 0:00:49] } 12. Qa4+ { [%clk 0:00:35] } Nc6 { [%clk 0:00:47] } 13. Nxc6 { [%clk 0:00:33] } bxc6 { [%clk 0:00:36] } 14. Qxc6+ { [%clk 0:00:31] } Kf8 { [%clk 0:00:34] } 15. Bxd6+ { [%clk 0:00:27] } cxd6 { [%clk 0:00:33] } 16. Qf3+ { [%clk 0:00:25] } Nf6 { [%clk 0:00:32] } 17. Nd5 { [%clk 0:00:23] } h5 { [%clk 0:00:28] } 18. Rae1 { [%clk 0:00:22] } g5 { [%clk 0:00:19] } 19. Re6 { [%clk 0:00:21] } Kg7 { [%clk 0:00:10] } 20. Rxf6 { [%clk 0:00:13] } Re8 { [%clk 0:00:08] } 21. Rf7+ { [%clk 0:00:10] } Kh6 { [%clk 0:00:07] } 22. Qf6+ { [%clk 0:00:09] } Qxf6 { [%clk 0:00:06] } 23. Rxf6+ { [%clk 0:00:08] } Kg7 { [%clk 0:00:05] } 24. Rxd6 { [%clk 0:00:07] } Re4 { [%clk 0:00:04] } 25. Rd7+ { [%clk 0:00:04] } Kg6 { [%clk 0:00:02] } 26. d4 { [%clk 0:00:03] } Rxd4 { [%clk 0:00:00] } 27. Ne3 { [%clk 0:00:00] } 1-0

This topic has been archived and can no longer be replied to.